diff -ur --new-file old/linux/CREDITS new/linux/CREDITS --- old/linux/CREDITS Sun Jan 4 19:40:15 1998 +++ new/linux/CREDITS Mon Mar 16 23:27:03 1998 @@ -33,6 +33,13 @@ S: B-2610 Wilrijk-Antwerpen S: Belgium +N: C. Scott Ananian +E: cananian@alumni.princeton.edu +W: http://www.pdos.lcs.mit.edu/~cananian +P: 1024/85AD9EED AD C0 49 08 91 67 DF D7 FA 04 1A EE 09 E8 44 B0 +D: Unix98 pty support. +D: APM update to 1.2 spec. + N: Erik Andersen E: andersee@debian.org W: http://www.inconnect.com/~andersen @@ -55,9 +62,10 @@ N: Andrea Arcangeli E: arcangeli@mbox.queen.it -W: http://www-linux.deis.unibo.it/~mirror/ +W: http://www.cs.unibo.it/~arcangel/ P: 1024/CB4660B9 CC A0 71 81 F4 A0 63 AC C0 4B 81 1D 8C 15 C8 E5 -D: parport sharing fix. Various other kernel hacks. +D: Parport sharing hacker. +D: Various other kernel hacks. S: Via Ciaclini 26 S: Imola 40026 S: Italy @@ -124,10 +132,12 @@ S: Germany N: Fred Baumgarten -E: dc6iq@insu1.etec.uni-karlsruhe.de +E: dc6iq@insl1.etec.uni-karlsruhe.de +E: dc6iq@adacom.org +E: dc6iq@db0ais.#hes.deu.eu (packet radio) D: NET-2 & netstat(8) -S: Kandelstrasse 27 -S: 76297 Stutensee +S: Soevener Strasse 11 +S: 53773 Hennef S: Germany N: Donald Becker @@ -202,6 +212,14 @@ S: Columbus, Ohio 43210 S: USA +N: Peter Braam +E: braam@cs.cmu.edu +W: http://coda.cs.cmu.edu/~braam +D: Coda Filesystem +S: Dept of Computer Science +S: 5000 Forbes Ave +S: Pittsburgh PA 15213 + N: Andries Brouwer E: aeb@cwi.nl D: random Linux hacker @@ -356,7 +374,7 @@ N: Eddie C. Dost E: ecd@skynet.be D: Linux/Sparc kernel hacker -D: New Linux/Sparc maintainer (while davem is at SGI) +D: Linux/Sparc maintainer S: Rue de la Chapelle 51 S: 4850 Moresnet S: Belgium @@ -378,6 +396,11 @@ S: Blacksburg, Virginia 24061 S: USA +N: Cyrus Durgin +E: cider@speakeasy.org +W: http://www.speakeasy.org/~cider/ +D: implemented kmod + N: Torsten Duwe E: Torsten.Duwe@informatik.uni-erlangen.de D: Part-time kernel hacker @@ -420,11 +443,11 @@ S: Sweden N: Paal-Kristian Engstad -E: engstad@funcom.com +E: engstad@intermetrics.com D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.) -S: Oscars gt. 35 -S: N-0258 OSLO -S: Norway +S: 17101 Springdale Street #225 +S: Huntington Beach, California 92649 +S: USA N: Doug Evans E: dje@cygnus.com @@ -465,11 +488,12 @@ S: Germany N: Jeremy Fitzhardinge -E: jeremy@sw.oz.au +E: jeremy@zip.com.au D: Improved mmap and munmap handling D: General mm minor tidyups -S: 99 Albermarle Street -S: Newtown 2042 +S: 67 Surrey St. +S: Darlinghurst, Sydney +S: NSW 2010 S: Australia N: Ralf Flaxa @@ -550,11 +574,11 @@ S: Australia N: Dmitry S. Gorodchanin -E: begemot@bgm.rosprint.net +E: pgmdsg@ibi.com D: RISCom/8 driver, misc kernel fixes. -S: 6/1 M.Koneva bl, apt #125 -S: Poltava 314023 -S: Ukraine +S: 4 Main Street +S: Woodbridge, Connecticut 06525 +S: USA N: Paul Gortmaker E: gpg109@rsphy1.anu.edu.au @@ -674,6 +698,11 @@ S: D - 72072 Tuebingen S: Germany +N: Jauder Ho +E: jauderho@transmeta.com +D: bug toaster (A1 sauce makes all the difference) +D: Transmeta BOFH in my free time + N: Dirk Hohndel E: hohndel@aib.com D: The XFree86[tm] Project @@ -705,6 +734,7 @@ N: Ron Holt E: ron@caldera.com W: http://www.holt.org/ +P: 1024/1FD44539 DF 4B EB 9F 5B 68 38 9A 40 E3 FB 71 D1 C8 0B 56 D: Kernel development D: Minor kernel modifications to support Wabi and Wine S: Caldera, Inc. @@ -728,6 +758,16 @@ S: Wantage, New Jersey 07461 S: USA +N: Harald Hoyer +E: HarryH@Royal.Net +W: http://hot.spotline.de/ +W: http://home.pages.de/~saturn +D: ip_masq_quake +D: md boot support +S: Alleenstrasse 27 +S: D-71679 Asperg +S: Germany + N: Miguel de Icaza Amozurrutia E: miguel@nuclecu.unam.mx D: Linux/SPARC team, Midnight Commander maintainer @@ -811,6 +851,12 @@ S: D-64283 Darmstadt S: Germany +N: Russell King +E: rmk@arm.uk.linux.org +D: Linux/arm integrater, maintainer & hacker +S: Burgh Heath, Tadworth, Surrey. +S: England + N: Olaf Kirch E: okir@monad.swb.de D: Author of the Linux Network Administrators' Guide @@ -820,9 +866,11 @@ N: Ian Kluft E: ikluft@thunder.sbay.org -D: Smail binary packages for Slackware and Debian -S: 2200 Monroe Street #1509 -S: Santa Clara, California 95050-3452 +W: http://www.kluft.com/~ikluft/ +D: NET-1 beta testing & minor patches, original Smail binary packages for +D: Slackware and Debian, vote-taker for 2nd comp.os.linux reorganization +S: PO Box 611311 +S: San Jose, CA 95161-1311 S: USA N: Alain L. Knaff @@ -897,8 +945,8 @@ N: Bas Laarhoven E: bas@vimec.nl D: Loadable modules and ftape driver -S: Mr. v. Boemellaan 39 -S: NL-5237 KA 's-Hertogenbosch +S: J. Obrechtstr 23 +S: NL-5216 GP 's-Hertogenbosch S: The Netherlands N: Savio Lam @@ -977,6 +1025,14 @@ S: Nepean, Ontario S: Canada K2H 6S3 +N: Jamie Lokier +E: jamie@imbolc.ucc.ie +D: Reboot-through-BIOS for broken 486 motherboards +S: 26 Oatlands Road +S: Oxford +S: OX2 0ET +S: United Kingdom + N: Warner Losh E: imp@village.org D: Linux/MIPS Deskstation support, Provided OI/OB for Linux @@ -1014,7 +1070,7 @@ N: Pavel Machek E: pavel@atrey.karlin.mff.cuni.cz D: Softcursor for vga, hypertech cdrom support, vcsa bugfix -D: Network block device +D: Network block device, sun4/330 port S: Volkova 1131 S: 198 00 Praha 9 S: Czech Republic @@ -1092,8 +1148,8 @@ N: Dirk Melchers E: dirk@merlin.nbg.sub.org D: 8 bit XT hard disk driver for OMTI5520 -S: Heidackerstrass 19 -S: D-91056 Erlangen +S: Schloessleinsgasse 31 +S: D-90453 Nuernberg S: Germany N: Michael Meskes @@ -1140,12 +1196,13 @@ D: New Linux-Activists maintainer D: Linux Emacs elf/qmagic support + other libc/gcc things D: Yee bore de yee bore! ;-) -S: 2 Bristol Court -S: East Brunswick, New Jersey 08816 +S: 111 Alta Tierra Court +S: Los Gatos, CA 95032 S: USA N: Rick Miller E: rdmiller@execpc.com +W: http://www.execpc.com/~rdmiller/ D: Original Linux Device Registrar (Major/minor numbers) D: au-play, bwBASIC S: S78 W16203 Woods Road @@ -1286,6 +1343,7 @@ N: Kirk Petersen E: kirk@speakeasy.org W: http://www.speakeasy.org/~kirk/ +D: implemented kmod D: modularized BSD Unix domain sockets N: Kai Petzke @@ -1309,8 +1367,12 @@ D: Some PCI kernel support N: Stefan Probst -E: snprobst@immd4.informatik.uni-erlangen.de -D: The Linux Support Team Erlangen +E: sp@caldera.de +D: The Linux Support Team Erlangen, 1993-97 +S: Caldera (Deutschland) GmbH +S: Lazarettstrasse 8 +S: 91054 Erlangen +S: Germany N: Daniel Quinlan E: quinlan@pathname.com @@ -1335,16 +1397,18 @@ S: USA N: Stefan Reinauer -E: stepan@home.culture.mipt.ru -W: http://home.culture.mipt.ru/~stepan -D: Modularized affs and ufs. Minor fixes. -S: Rebmannsweg 34h -S: 79539 Loerrach +E: stepan@linux.de +W: http://www.freiburg.linux.de/~stepan/ +D: Modularization of some filesystems +D: /proc/sound, minor fixes +S: Schlossbergring 9 +S: 79098 Freiburg S: Germany N: Joerg Reuter -E: jreuter@lykos.oche.de -E: dl1bke@db0pra.ampr.org +E: jreuter@poboxes.com +W: http://www.rat.de/jr/ +W: http://qsl.net/dl1bke/ D: Generic Z8530 driver, AX.25 DAMA slave implementation D: Several AX.25 hacks @@ -1356,6 +1420,15 @@ S: 75019 Paris S: France +N: Rik van Riel +E: H.H.vanRiel@fys.ruu.nl +W: http://www.fys.ruu.nl/~riel/ +D: Maintainer of the mm-patches page (see www.linuxhq.com) +D: Documentation/sysctl/*, kswapd fixes, random kernel hacker +S: Vorenkampsweg 1 +S: NL-9488 TG Zeijerveld +S: The Netherlands + N: William E. Roadcap E: roadcapw@cfw.com W: http://www.cfw.com/~roadcapw @@ -1565,7 +1638,7 @@ W: http://www.cs.helsinki.fi/~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: 3665 Benton Street #36 +S: 1050 Woodduck Avenue S: Santa Clara, California 95051 S: USA @@ -1651,6 +1724,14 @@ S: 97078 Wuerzburg S: Germany +N: Greg Ungerer +E: gerg@stallion.com +D: Author of Stallion multiport serial drivers +S: Stallion Technologies +S: 33 Woodstock Rd +S: Toowong, QLD. 4066 +S: Australia + N: Jeffrey A. Uphoff E: juphoff@nrao.edu E: jeff.uphoff@linux.org @@ -1674,6 +1755,13 @@ S: 90491 Nuernberg S: Germany +N: Petr Vandrovec +E: vandrove@vc.cvut.cz +D: Small contributions to ncpfs +S: Chudenicka 8 +S: 10200 Prague 10, Hostivar +S: Czech Republic + N: Dirk Verworner D: Co-author of german book ``Linux-Kernel-Programmierung'' D: Co-founder of Berlin Linux User Group @@ -1785,10 +1873,12 @@ S: The Netherlands N: David Woodhouse -E: dwmw2@cam.ac.uk +E: Dave@imladris.demon.co.uk D: Extensive ARCnet rewrite D: ARCnet COM20020, COM90xx IO-MAP drivers D: SO_BINDTODEVICE in 2.1.x (from Elliot Poger's code in 2.0.31) +D: Contributed to NCPFS rewrite for 2.1.x dcache +D: Alpha platforms: SX164, LX164 and Ruffian ported to 2.1.x S: Robinson College, Grange Road S: Cambridge. CB3 9AN S: England diff -ur --new-file old/linux/Documentation/00-INDEX new/linux/Documentation/00-INDEX --- old/linux/Documentation/00-INDEX Sun Dec 28 21:05:44 1997 +++ new/linux/Documentation/00-INDEX Thu Feb 26 20:01:24 1998 @@ -6,6 +6,8 @@ 00-INDEX - this file. +ARM-README + - information for using Linux on the ARM architecture. BUG-HUNTING - brute force method of doing binary search of patches to find bug. Changes @@ -14,10 +16,14 @@ - how the boss likes the C code in the kernel to look. Configure.help - text file that is used for help when you run "make config" +IO-APIC.txt + - info on using the enhanced interrupt hardware on SMP boards. IO-mapping.txt - how to access I/O mapped memory from within device drivers. SMP.txt - notes, and "To Fix" list for multi-processor Linux. (see smp.tex) +VGA-softcursor.txt + - how to change your VGA cursor from a blinking underscore. binfmt_misc.txt - info on the kernel support for extra binary formats. cdrom/ @@ -36,6 +42,8 @@ - directory with info on the various filesystems that Linux supports. ftape.txt - notes about the floppy tape device driver +hayes-esp.txt + - info on using the Hayes ESP serial driver. ide.txt - important info for users of ATA devices (IDE/EIDE disks and CD-ROMS) initrd.txt @@ -46,32 +54,44 @@ - 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. locks.txt - info on file locking implementations, flock() vs. fcntl(), etc. logo.gif - Full colour GIF image of Linux logo (penguin) logo.txt - Info on creator of above logo & site to get additional images from. +m68k/ + - directory with info about Linux on Motorola 68k archtecture. 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. +md.txt + - info on boot arguments for the multiple devices driver memory.txt - info on typical Linux memory problems. mca.txt - info on supporting Micro Channel Architecture (e.g. PS/2) systems. modules.txt - short guide on how to make kernel parts into loadable modules +nbd.txt + - info on a TCP implementation of a network block device. networking/ - directory with info on various linux networking aspects. nfsroot.txt - short guide on setting up a diskless box with NFS root filesystem oops-tracing.txt - how to decode those nasty internal kernel error dump messages. +pcwd-watchdog.txt + - info and sample code for using with the PC Watchdog reset card. paride.txt - information about the parallel port IDE subsystem. parport.txt - how to use the parallel-port driver. +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 @@ -80,10 +100,22 @@ - notes on how to use the Real Time Clock (aka CMOS clock) driver. 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. +smart-config.txt + - description of the Smart Config makefile feature. smp.tex - TeX document describing implementation of Multiprocessor Linux +specialix.txt + - info on hardware/driver for specialix IO8+ multiport serial card. +spinlocks.txt + - info on using spinlocks to provide exclusive access in kernel. +stallion.txt + - info on using the Stallion multiport serial driver. svga.txt - short guide on selecting video modes at boot via VGA BIOS. +transname.txt + - how to use name translation to ease use of diskless systems. unicode.txt - info on the Unicode character/font mapping used in Linux. watchdog.txt 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 Wed Jan 21 01:39:41 1998 @@ -0,0 +1,169 @@ + ARM Linux 2.1.78 + ================ + + ** The ARM support contained within is NOT complete - it will not build. ** + ** If you want to build it, then please obtain a full copy of the ARM ** + ** patches from ftp://ftp.arm.uk.linux.org/pub/armlinux/kernel-sources/v2.1 ** + + Since this is a development kernel, it will not be as stable as the 2.0 + series, and can cause very nasty problems (eg, trashing your hard disk). + When running one of these kernels, I advise you to back up the complete + contents of all your hard disks. + +Contributors +------------ + + Here is a list of people actively working on the project (If you + wish to be added to the list, please email me): + + Name: Russell King + Mail: linux@arm.uk.linux.org + Desc: Original developer of ARM Linux, project co-ordinator. + + Name: Dave Gilbert + Mail: linux@treblig.org + Desc: A3/4/5xx floppy and hard disk code maintainer. + + Name: Philip Blundell + Mail: Philip.Blundell@pobox.com + Desc: Architecture and processor selection during make config. + +Todo list +--------- + + This is the list of changes to be done (roughly prioritorised): + + * fully test new A5000 & older MEMC translation code + * fully test new AcornSCSI driver. + * reply to email ;) + +Bugs +---- + + Fixed bugs in this version 2.1.76: + + Modules believed to be buggy (please report your successes/failures): + + * AcornSCSI believed to occasionally corrupt hard drives. + * All NCR5380-based SCSI devices [Cumana I, Oak, EcoSCSI] are slow, + and may not allow write access. + * A5000 and older machine kernel builds may not be as stable as they were. + + Notes + ===== + +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 is good. + + 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=/usr/src/bin/arm/arm-linuxelf- + + Do a 'make config', followed by 'make dep', and finally 'make all' to + build the kernel (vmlinux). A compressed image can be built by doing + a 'make zImage' instead of 'make all'. + +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 + kernels unless they come to me (or the relevant person concerned). + + When sending bug reports, please ensure that they contain all relevent + information, eg. the kernel messages that were printed before/during + the problem, what you were doing, etc. + + For patches, please include some explaination as to what the patch does + and why (if relevent). + +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. + +Kernel initialisation abort codes +--------------------------------- + + When the kernel is unable to boot, it will if possible display a colour + 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: + Kernel does not support the processor architecture detected. + +Request to developers +--------------------- + + When writing device drivers which include a separate assember 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 needlessly 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 its 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. diff -ur --new-file old/linux/Documentation/Changes new/linux/Documentation/Changes --- old/linux/Documentation/Changes Sun Nov 30 21:23:16 1997 +++ new/linux/Documentation/Changes Wed Mar 18 06:22:25 1998 @@ -14,10 +14,10 @@ therefore owes credit to the same people as that file (Jared Mauch, Axel Boldt, Alessandro Sigala, and countless other users all over the 'net). Please feel free to submit changes, corrections, gripes, -flames, money, etc. to me (gt1355b@prism.gatech.edu). If you do so, -you don't need to bother doing so in the form of a diff, as this is -generated by texinfo so a diff is useless anyway (though I can -incorporate one by hand if you insist upon sending it that way ;-). +flames, money, etc. to me (kaboom@gatech.edu). If you do so, you don't +need to bother doing so in the form of a diff, as this is generated by +texinfo so a diff is useless anyway (though I can incorporate one by +hand if you insist upon sending it that way ;-). Check out http://www.cviog.uga.edu/Misc/info/LinuxBleed.html for an HTML-ized shopping list. @@ -26,8 +26,14 @@ http://www.datanet.hu/generations/linux/Changes2.html is an English-language HTML version. -Last updated: September 13. 1997 -Current Author: Chris Ricker (gt1355b@prism.gatech.edu). + The most current version should always be available from +http://cyberbuzz.gatech.edu/kaboom/linux/ as well. + + Also, don't forget http://www.linuxhq.com/ for all your Linux kernel +needs. + +Last updated: March 16. 1998 +Current Author: Chris Ricker (kaboom@gatech.edu). Current Minimal Requirements **************************** @@ -36,21 +42,24 @@ encountered a bug! If you're unsure what version you're currently running, the suggested command should tell you. -- Kernel modules modutils-2.1.55 ; insmod -V +- Kernel modules modutils-2.1.85 ; insmod -V - Gnu C 2.7.2.3 ; gcc --version - Binutils 2.8.1.0.1 ; ld -v -- Linux C Library 5.4.38 ; ls -l /lib/libc.so.* +- Linux C Library 5.4.44 ; ls -l /lib/libc.so.* - Dynamic Linker (ld.so) 1.9.5 ; ldd -v - Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.* -- Procps 1.2 ; ps --version -- Procinfo 0.11 ; procinfo -v -- Mount 2.6h ; mount --version +- Procps 1.2.5 ; ps --version +- Procinfo 0.13 ; procinfo -v +- Mount 2.7l ; mount --version - Net-tools 1.41 ; hostname -V - Loadlin 1.6a - Sh-utils 1.16 ; expr --v -- Autofs 0.3.11 ; automount --version +- Autofs 0.3.11 ; automount --version - NFS 0.4.21 ; showmount --version - Bash 1.14.7 ; bash -version +- Ncpfs 2.1.1 ; ncpmount -v +- Pcmcia-cs 3.0.0 +- PPP 2.3.3 ; pppd -v Upgrade notes ************* @@ -64,6 +73,10 @@ in Lilo. A small number of machines need "reboot=bios" to reboot via the BIOS. + Also, please remember that cua* devices are now obsolete. Switch to +the corresponding ttyS* device instead (e.g., cua0 -> ttyS0, cua1 -> +ttyS1, etc.). + Libc ==== @@ -76,7 +89,7 @@ For modules to work, you need to be running libc-5.4.x or greater. Since updates to libc fix other problems as well (security flaws, for example) and since 5.4.7 is missing a few needed symbols, try to get -the latest 5.4.x you can. Currently, libc-5.4.38 is the latest public +the latest 5.4.x you can. Currently, libc-5.4.44 is the latest public release. If you upgrade to libc-5.4.x, you also have to upgrade your dynamic @@ -90,12 +103,22 @@ If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if you're using NIS. + If you upgrade to libc-5.4.44, please read and pay attention to its +accompanying release notes. The section about it breaking make is not +a joke. + Modules ======= - You need to upgrade to modutils-2.1.55 for kernels 2.1.55 and later. + You need to upgrade to modutils-2.1.85 for kernels 2.1.85 and later. This version will also work with 2.0.x kernels. + As of 2.1.90-pre1, kerneld has been replaced by a kernel thread, +kmod. See Documentation/kmod.txt for more information. The main +user-level change this requires is modification to your init scripts to +check for the absence of /proc/sys/kernel/modprobe before starting +kerneld. + Binutils ======== @@ -108,9 +131,13 @@ You need at least GCC 2.7.2 to compile the kernel. If you're upgrading from an earlier release, you might as well get GCC 2.7.2.3, -the latest public release. If you already have GCC 2.7.2 on your -system, you don't have to upgrade just so the kernel will work (though -feel free to upgrade if you want the gcc bug fixes). +the latest stable public release. If you already have GCC 2.7.2 on +your system, you don't have to upgrade just so the kernel will work +(though feel free to upgrade if you want the gcc bug fixes). + + Note that the latest compilers (egcs, pgcc, gcc 2.8) may do Bad +Things while compiling your kernel, particularly if absurd +optimizations (like -O9) are used. Caveat emptor. Networking Changes ================== @@ -131,7 +158,7 @@ presence. To turn on IP forwarding, issue the following command: echo 1 > -/proc/sys/net/ipv4/ip_forwarding +/proc/sys/net/ipv4/ip_forward To run bootpd, you'll need to issue the following command: echo 1 >/proc/sys/net/ipv4/ip_boot_agent @@ -190,18 +217,13 @@ /dev/lp0 with the new Plug-and-Play driver. If printing breaks with the new driver, try checking your lpd configuration. -pppd -==== -This kernel version needs a minor bugfix to pppd. See -Documentation/networking/ppp.txt for more information. - Syncookies ========== -When you build your kernel with Syncookie support (CONFIG_SYN_COOKIES) -the syncookie code still defaults to off (unlike the 2.0.30+ behaviour). -You have to explicitely enable it by add a line like -echo 1 >/proc/sys/net/ipv4/tcp_syncookies -to one of your startup scripts (e.g. /etc/rc.d/rc.local on a redhat system) + + 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 Bash ==== @@ -210,6 +232,24 @@ cause problems when compiling modules. Upgrade to at least 1.14 to fix this problem. +Ncpfs +===== + + To mount NetWare shares, you'll need to upgrade to a more recent +version of the ncpfs utils. + +Pcmcia-cs +========= + + If you use pcmcia cards, you'll need to upgrade the daemon and +support utils to the latest release of pcmcia-cs. + +PPP +=== + + Due to changes in the routing code, those of you using PPP +networking will need to upgrade your pppd. + Where to get the files ********************** @@ -236,12 +276,12 @@ Linux C Library =============== -The 5.4.38 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.38.bin.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.38.bin.tar.gz +The 5.4.44 release: +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.44.bin.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.44.bin.tar.gz Installation notes for 5.4.38: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.38 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.38 +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.44 +ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.44 Linux C++ Library ================= @@ -263,22 +303,22 @@ Modules utilities ================= -The 2.1.55 release: -ftp://ftp.redhat.com/pub/alphabits/modutils/modutils-2.1.55.tar.gz -ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.55.tar.gz +The 2.1.85 release: +ftp://ftp.redhat.com/pub/alphabits/modutils/modutils-2.1.85.tar.gz +ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.85.tar.gz Procps utilities ================ The 1.2 release: -ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.tar.gz -ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.tgz +ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.5.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.5.tgz Procinfo utilities ================== The 0.11 release: -ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.11.tar.gz +ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.13.tar.gz RPM utilities ============= @@ -317,8 +357,8 @@ Mount ===== -The 2.6h release: -ftp://ftp.win.tue.nl/pub/linux/util/mount-2.6h.tar.gz +The 2.7l release: +ftp://ftp.win.tue.nl/pub/linux/util/mount/mount-2.7l.tar.gz Autofs ====== @@ -336,9 +376,8 @@ Net-tools ========= -The 1.41 release: -ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz -ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz +The 1.432 release: +ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.432.tar.gz Ypbind ====== @@ -352,6 +391,25 @@ The 1.14.7 release: ftp://prep.ai.mit.edu/pub/gnu/bash-1.14.7.tar.gz +Ncpfs +===== + +The 2.1.1 release: +ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.1.1.tgz +ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/ncpfs/ncpfs-2.1.1.tgz + +Pcmcia-cs +========= + +The 3.0.0 release: +ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs-3.0.0.tar.gz + +PPP +=== + +The 2.3.3 release: +ftp://cs.anu.edu.au/pub/software/ppp/ppp-2.3.3.tar.gz + Other Info ========== @@ -367,11 +425,12 @@ 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://ftp.redhat.com/pub/contrib/ will have almost -everything you need. +everything you need, as does RedHat 5.0. Those of you running Debian (or a different distribution that supports .deb packages) can look in the "unstable" and -"project/experimental" directories of your favorite Debian mirror. +"project/experimental" directories of your favorite Debian mirror. The +Debian 2.0 release should have most packages you need as well. For others, David Bourgin has put together a package of everything necessary to quickly and easily upgrade to 2.1.x. See @@ -380,5 +439,5 @@ Please send info about any other packages that 2.1.x "broke" or about any new features of 2.1.x that require extra or new packages for use to -Chris Ricker (gt1355b@prism.gatech.edu). +Chris Ricker (kaboom@gatech.edu). diff -ur --new-file old/linux/Documentation/Configure.help new/linux/Documentation/Configure.help --- old/linux/Documentation/Configure.help Fri Mar 27 02:41:48 1998 +++ new/linux/Documentation/Configure.help Fri Mar 27 02:42:25 1998 @@ -103,6 +103,17 @@ you are not sure, say Y; apart from resulting in a 45kB bigger kernel, it won't hurt. +Max physical memory +CONFIG_MAX_MEMSIZE + Linux/x86 can use up to 3.8 gigabytes of physical memory. Default + is max 1 gigabyte physical memory (1024 MB), this is enough for + most systems. + A system with 2G physical memory should use a value of ~2400, a + system with 3.8G memory should use something like 3900. A bit of + experimentation with the limit wont hurt, the kernel needs a ~128M + window for vmalloc() plus PCI space uses up some memory too, thus + addresses above FD000000 should rather be kept free. + Normal floppy disk support CONFIG_BLK_DEV_FD If you want to use your floppy disk drive(s) under Linux, say @@ -479,6 +490,17 @@ MicroSolutions backpack PD/CD drive and the Imation Superdisk LS-120 drive. +Parallel port ATAPI tapes +CONFIG_PARIDE_PT + This option enable the high-level driver for ATAPI tape devices + connected through a parallel port. If you chose to build PARIDE + support into your kernel, you may answer Y here to build in the + parallel port ATAPI disk driver, otherwise you should answer M + to build it as a loadable module. The module will be called pt.o. + You must also have at least one parallel port protocol driver in + your system. Among the devices supported by this driver is the + parallel port version of the HP 5GB drive. + ATEN EH-100 protocol CONFIG_PARIDE_ATEN This option enables support for the ATEN EH-100 parallel port IDE @@ -647,6 +669,11 @@ want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say Y. +Boot support (linear, striped) +CONFIG_MD_BOOT + To boot with an initial linear or striped md device you have to + select this. For lilo and loadlin options see Documentation/md.txt. + Support for Deskstation RPC44 CONFIG_DESKSTATION_RPC44 This is a machine with a R4400 100 MHz CPU. To compile a Linux @@ -725,6 +752,29 @@ see http://www.inka.de/sites/lina/linux/NetTools/index_en.html for details. +Fast switching (read help!) +CONFIG_NET_FASTROUTE + Enable direct NIC-to-NIC data transfers. + *** This option is NOT COMPATIBLE with several important *** + *** networking options: especially CONFIG*FIREWALL. *** + However, it will work with all options in CONFIG_IP_ADVANCED_ROUTER + section (except for CONFIG_IP_ROUTE_TOS). At the moment few of devices + supports it (tulip is one of them, modified 8390 can be found at + ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). + Remember, short cuts make long delays :-), say N. + +Forwarding between high speed interfaces +CONFIG_NET_HW_FLOWCONTROL + This option enables NIC hardware throttling during periods of + extremal congestion. At the moment only couple of device drivers + support it (really, one --- tulip, modified 8390 can be found + at ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). + Really, this option is applicable to any machine attached + to enough fast network, and even 10Mb NIC + is able to kill not very slow box, sort of 120MHz Pentium. + However, do not enable this option, if you did not experienced + any serious problems. + Network aliasing CONFIG_NET_ALIAS This will allow you to set multiple network addresses on the same @@ -1159,6 +1209,12 @@ Ultra/AX machines. This code is also available as a module (say M), called parport_ax.o. If in doubt, saying N is the safe plan. +Foreign parallel hardware +CONFIG_PARPORT_OTHER + Say Y here if you want to be able to load driver modules to support + other types of parallel port. This causes a performance loss, so most + people say N. + Compile the kernel into the ELF object format CONFIG_ELF_KERNEL ELF (Executable and Linkable Format) is a format for libraries and @@ -1281,21 +1337,12 @@ non-kernel sources, you would benefit from this option. Otherwise it's not that important. So, N ought to be a safe bet. -Kernel daemon support -CONFIG_KERNELD - Normally when you have selected some drivers and/or filesystems to - be created as loadable modules, you also have the responsibility to - load the corresponding module (via insmod/modprobe) before you can - use it. If you select Y here, the kernel will take care of this all - by itself, together with the user level daemon "kerneld". Note that - "kerneld" will also automatically unload all unused modules, so you - don't have to use "rmmod" either. kerneld will also provide support - for different user-level beeper and screen blanker programs later - on. The "kerneld" daemon is included in the modutils package (check - Documentation/Changes for latest version and location). You will - probably want to read the kerneld mini-HOWTO, available via ftp - (user: anonymous) from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If unsure, say Y. +Kernel module loader support +CONFIG_KMOD + This feature allows the kernel to load modules for itself. When + a part of the kernel needs a module, it runs modprobe with the + appropriate arguments. Say Y here and read about configuring it + in Documentation/kmod.txt. (this is a replacement of kerneld) ARP daemon support (EXPERIMENTAL) CONFIG_ARPD @@ -2148,10 +2195,9 @@ (user: anonymous) from shadow.cabi.net in /pub/Linux. Note that if your box acts as a bridge, it probably contains several ethernet devices, but the kernel is not able to recognize more than one at - boot time without help; for details read the - Multiple-Ethernet-mini-HOWTO, available via ftp (user: anonymous) in - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The Bridging code is - still in test. If unsure, say N. + boot time without help; for details read the Ethernet-HOWTO, available + via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO/. + The Bridging code is still in test. If unsure, say N. Packet socket CONFIG_PACKET @@ -2770,29 +2816,54 @@ IBMMCA SCSI support CONFIG_SCSI_IBMMCA - If your computer sports an MCA bus system architecture (IBM PS/2) - with an SCSI harddrive, say Y here. Please read - Documentation/mca.txt. 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 ibmmca.o. If you want - to compile it as a module, say M here and read - Documentation/modules.txt. - Normally, all IBM MCA SCSI adapters are automatically detected. If - that doesn't work right however, you can completely override - auto-detection by specifying "ibmmcascsi=io1,io2,..." at the boot - loader's command prompt or "io_port=io1,io2,... scsi_id=id1,id2,..." - as a parameter of insmod. "io" and "id" are the I/O base address - and the SCSI ID of each adapter, respectively. - 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 ibmmca.o. - -reset SCSI-devices while booting -CONFIG_SCSI_IBMMCA_DEV_RESET - If you say Y here, each connected SCSI device will get a reset - command at boot time. This can be necessary for some special SCSI - devices. If unsure, say N. + This is support for the IBM SCSI adapter found in many of the PS/2 + series. CONFIG_MCA must be set for this to work. If the adapter + isn't found during boot (a common problem for models 56, 57, 76, and + 77) you'll need to use the 'ibmmcascsi=', where is the id + of the SCSI subsystem (usually 7, but if that doesn't work check your + reference diskette). Owners of model 95 with a LED-matrix-display + can in addition activate some activity info like under OS/2, but more + informative, by setting 'ibmmcascsi=display' as additional kernel- + parameter. + +Standard SCSI-order +CONFIG_IBMMCA_SCSI_ORDER_STANDARD + In the PC-world and in most modern SCSI-BIOS-setups, SCSI-harddisks + are assigned to the driveletters, starting with the lowest SCSI-id + (physical number - pun) to be drive C:, as seen from DOS and similar + operating systems. When looking into papers, describing the + ANSI-SCSI-standard, this assignment of drives appears to be wrong. + The SCSI-standard follows a hardware-hierarchy which says, that + id 7 has the highest priority and id 0 the lowest. Therefore, the + hostadapters are still today everywhere placed as SCSI-id 7 by + default. In the SCSI-standard, the driveletters express the priority + of the disk. C: should be the harddisk or a partition on it, with the + highest priority. This must therefore be the disk with the highest + SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the + original definition of the SCSI-standard as also industrial- and + process-control-machines, like VME-CPUs running under realtime-OSs + (e.g. LynxOS, OS9) do. + If you like to run Linux on your MCA-machine with the same assignment, + of harddisks, as seen from e.g. DOS or OS/2 on your machine, which + is in addition conform to the SCSI-standard, you must say 'y' here. + This is also necessary for MCA-Linux-users who want to keep downward- + compatibility to older releases of the IBM-MCA-SCSI-driver (older than + driver-release 2.00 and older than June 1997). + If you like to have the lowest SCSI-id assigned as drive C:, as modern + SCSI-BIOS do, which is not conform to the standard, but widely spread + and common in the PC-world of today, you must say 'n' here. + +Reset SCSI-devices at boottime +CONFIG_IBMMCA_SCSI_DEV_RESET + By default, SCSI-devices are reset, when the machine is powered on. + However, some devices exist, like special-control-devices, + SCSI-CNC-machines, SCSI-printer or scanners of older type, that + do not reset, when switched on. If you say 'y' here, each device + along your SCSI-bus will get a reset-command after it has been + probed, while the kernel is booting. Say always 'n' here, if you + have no such strange SCSI-devices on your bus. If you say 'y' and + some more modern devices, like harddisks, do not like too much + resets, your system will hang when booting. Always IN2000 SCSI support CONFIG_SCSI_IN2000 @@ -3055,10 +3126,8 @@ the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape)). You'll have to say Y if your computer contains a network card that you want to use under linux - (make sure you know its name because you will be asked for it and - read the Ethernet-HOWTO; also, if you plan to use more than one - network card under linux, read the Multiple-Ethernet-mini-HOWTO, - available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini) or if you + (make sure you know its name because you will be asked for it and read + the Ethernet-HOWTO in sunsite.unc.edu:/pub/Linux/docs/HOWTO; or if you want to use SLIP (Serial Line Internet Protocol is the protocol used to send Internet traffic over telephone lines or nullmodem cables) or CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better @@ -3799,10 +3868,8 @@ CONFIG_NET_VENDOR_SMC If you have a network (ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available via ftp (user: anonymous) in - sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than - one network card under linux, read the Multiple-Ethernet-mini-HOWTO, - available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. Note that - the answer to this question doesn't directly affect the kernel: + sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the + answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all the questions about Western Digital cards. If you say Y, you will be asked for your specific card in the following questions. @@ -3816,10 +3883,7 @@ running kernel whenever you want). The module will be called wd.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. SMC Ultra support CONFIG_ULTRA @@ -3830,13 +3894,23 @@ from the running kernel whenever you want). The module will be called smc-ultra.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. Important: There have - been many reports that, with some motherboards mixing an SMC Ultra - and an Adaptec AHA1542 SCSI card causes corruption problems with - many operating systems. + Documentation/networking/net-modules.txt. + Important: There have been many reports that, with some motherboards + mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, + such as some BusLogic models) causes corruption problems with many + operating systems. The linux smc-ultra driver has a work-around for this + but keep it in mind if you have such a SCSI card and have problems. + +SMC Ultra32 EISA support +CONFIG_ULTRA + If you have a network (ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available via ftp (user: anonymous) in + sunsite.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 smc-ultra32.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. SMC 9194 Support CONFIG_SMC9194 @@ -3850,20 +3924,15 @@ inserted in and removed from the running kernel whenever you want). The module will be called smc9194.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. If you plan to use - more than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + well as Documentation/networking/net-modules.txt. Racal-Interlan (Micom) NI cards CONFIG_NET_VENDOR_RACAL If you have a network (ethernet) card belonging to this class, such as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO, available via ftp (user: anonymous) in - sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than - one network card under linux, read the Multiple-Ethernet-mini-HOWTO, - available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. Note that - the answer to this question doesn't directly affect the kernel: + sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the answer + to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all the questions about NI cards. If you say Y, you will be asked for your specific card in the following questions. @@ -3878,10 +3947,7 @@ running kernel whenever you want). The module will be called ni5010.o. If you want to compile it as a module, say M here and read Documentation/modules.txt as well as -xIO Documentation/networking/net-modules.txt. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. NI5210 support CONFIG_NI52 @@ -3892,10 +3958,7 @@ running kernel whenever you want). The module will be called ni52.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. NI6510 support CONFIG_NI65 @@ -3906,19 +3969,14 @@ running kernel whenever you want). The module will be called ni65.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. AMD LANCE and PCnet (AT1500 and NE2100) support CONFIG_LANCE If you have a network (ethernet) card of this type, say Y and read the Ethernet-HOWTO, available via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Some LinkSys cards are of - this type. If you plan to use more than one network card under - linux, read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + this type. 3COM cards CONFIG_NET_VENDOR_3COM @@ -3928,9 +3986,7 @@ this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all the questions about 3COM cards. If you say Y, you will be asked for your specific card in the - following questions. If you plan to use more than one network card - under linux, read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + following questions. 3c501 support CONFIG_EL1 @@ -3944,10 +4000,7 @@ from the running kernel whenever you want). The module will be called 3c501.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini - and don't use 3c501s. + Documentation/networking/net-modules.txt. 3c503 support CONFIG_EL2 @@ -3958,10 +4011,7 @@ running kernel whenever you want). The module will be called 3c503.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. 3c505 support CONFIG_ELPLUS @@ -3973,9 +4023,7 @@ removed from the running kernel whenever you want), say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. The module will be called - 3c505.o. If you plan to use more than one network card under linux, - read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + 3c505.o. 3c507 support CONFIG_EL16 @@ -3986,10 +4034,7 @@ running kernel whenever you want). The module will be called 3c507.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. 3c523 support CONFIG_ELMC @@ -4000,10 +4045,7 @@ running kernel whenever you want). The module will be called 3c523.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. 3c509/3c579 support CONFIG_EL3 @@ -4014,11 +4056,8 @@ inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. The module will be called - 3c509.o. If you plan to use more than one network card under linux, - read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If your card is not - working you may need to use the DOS setup disk to disable Plug & - Play mode, and to select the default media type. + 3c509.o. If your card is not working you may need to use the DOS setup + disk to disable Plug & Play mode, and to select the default media type. 3c590 series (592/595/597) "Vortex" support CONFIG_VORTEX @@ -4031,9 +4070,7 @@ running kernel whenever you want), say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. The module will be called - 3c59x.o. If you plan to use more than one network card under linux, - read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini + 3c59x.o. Other ISA cards CONFIG_NET_ISA @@ -4046,9 +4083,7 @@ directly affect the kernel: saying N will just cause this configure script to skip all the remaining ISA network card questions. If you say Y, you will be asked for your specific card in the following - questions. If you plan to use more than one network card under - linux, read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + questions. Generic ARCnet support CONFIG_ARCNET @@ -4065,10 +4100,7 @@ from the running kernel whenever you want). The module will be called arcnet.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. Enable arc0e (ARCnet "ether-encap" packet format) CONFIG_ARCNET_ETH @@ -4149,10 +4181,7 @@ running kernel whenever you want). The module will be called e2100.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. CS89x0 support CONFIG_CS89x0 @@ -4165,9 +4194,7 @@ running kernel whenever you want), say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. The module will be called - cs89x.o. If you plan to use more than one network card under linux, - read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + cs89x.o. DEPCA support CONFIG_DEPCA @@ -4178,9 +4205,7 @@ code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. The module will be - called depca.o. If you plan to use more than one network card under - linux, read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + called depca.o. EtherWorks 3 support CONFIG_EWRK3 @@ -4193,18 +4218,13 @@ running kernel whenever you want), say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. The module will be called - ewrk3.o. If you plan to use more than one network card under linux, - read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + ewrk3.o. SEEQ8005 support CONFIG_SEEQ8005 This is a driver for the SEEQ 8005 network (ethernet) card. If this is for you, read the Ethernet-HOWTO, available via ftp (user: - anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan - to use more than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO. AT1700 support CONFIG_AT1700 @@ -4215,9 +4235,7 @@ running kernel whenever you want). 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. The module will be called - at1700.o. If you plan to use more than one network card under linux, - read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + at1700.o. FMV-181/182/183/184 support CONFIG_FMV18X @@ -4228,10 +4246,7 @@ removed from the running kernel whenever you want). The module will be called fmv18x.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you use FMV-183 or + Documentation/networking/net-modules.txt. If you use FMV-183 or FMV-184 and it is not working, you may need to disable Plug & Play mode of the card. @@ -4245,10 +4260,7 @@ in and removed from the running kernel whenever you want). The module will be called eepro.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. EtherExpress support CONFIG_EEXPRESS @@ -4262,9 +4274,7 @@ running kernel whenever you want), say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. The module will be called - eexpress.o. If you plan to use more than one network card under - linux, read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + eexpress.o. AT&T WaveLAN & DEC RoamAbout DS support CONFIG_WAVELAN @@ -4285,10 +4295,7 @@ inserted in and removed from the running kernel whenever you want). The module will be called wavelan.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. If you plan to use - more than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + well as Documentation/networking/net-modules.txt. HP PCLAN+ (27247B and 27252A) support CONFIG_HPLAN_PLUS @@ -4299,10 +4306,7 @@ running kernel whenever you want). The module will be called hp-plus.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. HP PCLAN (27245 and other 27xxx series) support CONFIG_HPLAN @@ -4313,10 +4317,7 @@ running kernel whenever you want). The module will be called hp.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. HP 10/100VG PCLAN (ISA, EISA, PCI) support CONFIG_HP100 @@ -4327,9 +4328,7 @@ running kernel whenever you want), say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. The module will be called - hp100.o. If you plan to use more than one network card under linux, - read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + hp100.o. NE2000/NE1000 support CONFIG_NE2000 @@ -4341,28 +4340,21 @@ from the running kernel whenever you want). The module will be called ne.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. SK_G16 support CONFIG_SK_G16 If you have a network (ethernet) card of this type, say Y and read the Ethernet-HOWTO, available via ftp (user: anonymous) in - sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than - one network card under linux, read the Multiple-Ethernet-mini-HOWTO, - available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + sunsite.unc.edu:/pub/Linux/docs/HOWTO. EISA, VLB, PCI and on board controllers CONFIG_NET_EISA This is another class of network cards which attach directly to the bus. If you have one of those, say Y and read the Ethernet-HOWTO, available via ftp (user: anonymous) from - sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than - one network card under linux, read the Multiple-Ethernet-mini-HOWTO, - available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you - are unsure, say Y. Note that the answer to this question doesn't + sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you are unsure, say Y. + Note that the answer to this question doesn't directly affect the kernel: saying N will just cause this configure script to skip all the questions about this class of network cards. If you say Y, you will be asked for your specific card in the @@ -4372,10 +4364,7 @@ CONFIG_PCNET32 If you have a PCnet32 or PCnetPCI based network (ethernet) card, say Y here and read the Ethernet-HOWTO, available via ftp (user: - anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to - use more than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Ansel Communications EISA 3200 support CONFIG_AC3200 @@ -4386,10 +4375,7 @@ running kernel whenever you want). The module will be called ac3200.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. Racal-Interlan EISA ES3210 support CONFIG_ES3210 @@ -4400,10 +4386,7 @@ running kernel whenever you want). The module will be called es3210.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. Apricot Xen-II on board ethernet CONFIG_APRICOT @@ -4414,9 +4397,7 @@ running kernel whenever you want), say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. The module will be called - apricot.o. If you plan to use more than one network card under - linux, read the Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + apricot.o. Generic DECchip & DIGITAL EtherWORKS PCI/EISA CONFIG_DE4X5 @@ -4430,10 +4411,7 @@ from the running kernel whenever you want). The module will be called de4x5.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. DECchip Tulip (dc21x4x) PCI support CONFIG_DEC_ELCP @@ -4465,10 +4443,7 @@ from the running kernel whenever you want). The module will be called dgrs.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. EtherExpressPro/100 support CONFIG_EEXPRESS_PRO100 @@ -4479,10 +4454,7 @@ removed from the running kernel whenever you want). The module will be called eepro100.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. ICL EtherTeam 16i/32 support CONFIG_ETH16I @@ -4493,10 +4465,7 @@ running kernel whenever you want). The module will be called eth16i.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. If you plan to use more - than one network card under linux, read the - Multiple-Ethernet-mini-HOWTO, available from - sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + Documentation/networking/net-modules.txt. TI ThunderLAN support (EXPERIMENTAL) CONFIG_TLAN @@ -4556,9 +4525,7 @@ want to compile this driver as a module however ( = 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 de600.o. If you plan to use more than one network - card under linux, read the Multiple-Ethernet-mini-HOWTO, available - from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + will be called de600.o. D-Link DE620 pocket adapter support CONFIG_DE620 @@ -4571,9 +4538,7 @@ want to compile this driver as a module however ( = 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 de620.o. If you plan to use more than one network - card under linux, read the Multiple-Ethernet-mini-HOWTO, available - from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. + will be called de620.o. Token Ring driver support CONFIG_TR @@ -5440,6 +5405,55 @@ read Documentation/modules.txt. The module will be called ncpfs.o. Say N unless you are connected to a Novell network. +Packet signatures +CONFIG_NCPFS_PACKET_SIGNING + NCP allows to sign packets for stronger security. If you want + security, say Y. Normal users can leave it off. To be able to use + packet signing you must use ncpfs > 2.0.12. + +Proprietary file locking +CONFIG_NCPFS_IOCTL_LOCKING + Allows locking of records on remote volumes. Say N unless you have special + applications which are able to utilize this locking scheme. + +Clear remove/delete inhibit when needed +CONFIG_NCPFS_STRONG + Allows manipulation of files flagged as Delete or Rename Inhibit. + To use this feature you must mount volumes with the ncpmount parameter + "-s" (ncpfs-2.0.12 and newer). Say Y unless you are not mounting + volumes with -f 444. + +Use NFS namespace when available +CONFIG_NCPFS_NFS_NS + Allows you to utilize NFS namespace on NetWare servers. It brings you + case sensitive filesystems. Say Y. You can disable it at mount-time with + the -N nfs parameter of ncpmount. + +Use OS2/LONG namespace when available +CONFIG_NCPFS_OS2_NS + Allows you to utilize OS2/LONG namespace on NetWare servers. Filenames + in this namespace are limited to 255 characters, they are case + insensitive, and case in names is preserved. + Say Y. You can disable it at mount time with the -N os2 parameter of + ncpmount. + +Allow mounting of volume subdirectories +CONFIG_NCPFS_MOUNT_SUBDIR + Allows you to mount not only whole servers or whole volumes, but also + subdirectory from a volume. It can be used to reexport data and so on. + There is no reason why to say N, so Y is recommended unless you count + every byte. + To utilize this feature you must use ncpfs-2.0.12 or newer. + +NDS interserver authentication domains +CONFIG_NCPFS_NDS_DOMAINS + This allows storing NDS private keys into kernel space where it can be + used to authenticate another server as interserver NDS accesses need + it. You must use ncpfs-2.0.12.1 or newer to utilize this feature. + Say Y if you are using NDS connections to NetWare servers. Do not say Y + if security is primary for you because root can read your session + key (from /proc/kcore). + Amiga FFS filesystem support CONFIG_AFFS_FS The Fast File System (FFS) is the common filesystem used on @@ -6170,9 +6184,9 @@ loadable module called `zft-compressor.o' which contains code to support user transparent on-the-fly compression based on Ross William's lzrw3 algorithm will be produced. If you have enabled - auto-loading of kernel modules via `kerneld' (i.e. have said `Y' to - CONFIG_KERNELD) then `zft-compressor.o' will be loaded automatically - by zftape when needed. + the kernel module loader (i.e. have said `Y' to CONFIG_KMOD) then + `zft-compressor.o' will be loaded automatically by zftape when + needed. Despite of its name zftape does NOT use compression by default. The file Documentation/ftape.txt contains a short description of the most important changes in the file system interface compared to @@ -6480,6 +6494,13 @@ powers off the computer). As with the other APM options, this option may not work reliably with some APM BIOS implementations. +Ignore multiple suspend/standby events +CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + This option is necessary on the Thinkpad 560, but should work on all + other laptops. When the APM BIOS returns multiple suspend or standby + events while one is already being processed they will be ignored. + Without this the Thinkpad 560 has troubles with apmd, and pcmcia-cs. + Watchdog Timer Support CONFIG_WATCHDOG If you say Y here (and to one of the following options) and create a @@ -6623,12 +6644,6 @@ be called joystick.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -ARC console time -CONFIG_RTC_ARC - If you boot your Alpha using the ARC firmware, say Y here. This option - adjusts the RTC clock to take into account the different starting epoch - used by ARC. - Sound card support CONFIG_SOUND If you have a Sound Card in your Computer, i.e. if it can say more @@ -6663,6 +6678,16 @@ drivers/sound/Readme.cards file before answering this question. For an unknown card you may answer Y if the card claims to be SoundBlaster compatible. + +Are you using the IBM Mwave "emulation" of SB ? +CONFIG_SB_MWAVE + The IBM Mwave can do whats loosely describable as emulation of an 8bit + soundblaster if you load the right firmware from DOS warm boot and pray + and your machine happens to like you. Say Y if you are doing this as the + IRQ test normally fails on the mwave emulation. If you'd like real MWAVE + support 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] Generic OPL2/OPL3 FM synthesizer support CONFIG_ADLIB diff -ur --new-file old/linux/Documentation/IO-APIC.txt new/linux/Documentation/IO-APIC.txt --- old/linux/Documentation/IO-APIC.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/IO-APIC.txt Wed Feb 4 00:28:34 1998 @@ -0,0 +1,137 @@ + +most (all) Intel SMP boards have the so-called 'IO-APIC', which is +an enhanced interrupt controller, able to route hardware interrupts +to multiple CPUs, or to CPU groups. + +Linux supports the IO-APIC, but unfortunately there are broken boards +out there which make it unsafe to enable the IO-APIC unconditionally. +The Linux policy thus is to enable the IO-APIC only if it's 100% safe, ie.: + + - the board is on the 'whitelist' + + or - the board does not have PCI pins connected to the IO-APIC + + or - the user has overriden blacklisted settings with the + pirq= boot option line. + +Kernel messages tell you wether the board is 'safe'. If your box +boots with enabled IO-APIC IRQs, then you have nothing else to do. Your +/proc/interrupts will look like this one: + + ----------------------------> + hell:~> cat /proc/interrupts + CPU0 CPU1 + 0: 90782 0 XT PIC timer + 1: 4135 2375 IO-APIC keyboard + 2: 0 0 XT PIC cascade + 3: 851 807 IO-APIC serial + 9: 6 22 IO-APIC ncr53c8xx + 11: 307 154 IO-APIC NE2000 + 13: 4 0 XT PIC fpu + 14: 56000 30610 IO-APIC ide0 + NMI: 0 + IPI: 0 + <---------------------------- + +some interrupts will still be 'XT PIC', but this is not a problem, none +of those IRQ sources is 'heavy'. + +If one of your boot messages says 'unlisted/blacklisted board, DISABLING +IO-APIC IRQs', then you should do this to get multi-CPU IO-APIC IRQs +running: + + A) if your board is unlisted, then mail to linux-smp to get + it into either the white or the blacklist + B) if your board is blacklisted, then figure out the apropriate + pirq= option to get your system boot + + +pirq= lines look like the following in /etc/lilo.conf: + + append="pirq=15,11,10" + +the actual numbers depend on your system, on your PCI cards and on their +PCI slot position. Usually PCI slots are 'daisy chained' before they are +connected to the PCI chipset irq routing facility (the incoming PIRQ1-4 +lines): + + ,-. ,-. ,-. ,-. ,-. + PIRQ4 ----| |-. ,-| |-. ,-| |-. ,-| |--------| | + |S| \ / |S| \ / |S| \ / |S| |S| + PIRQ3 ----|l|-. `/---|l|-. `/---|l|-. `/---|l|--------|l| + |o| \/ |o| \/ |o| \/ |o| |o| + PIRQ2 ----|t|-./`----|t|-./`----|t|-./`----|t|--------|t| + |1| /\ |2| /\ |3| /\ |4| |5| + PIRQ1 ----| |- `----| |- `----| |- `----| |--------| | + `-' `-' `-' `-' `-' + +every PCI card emits a PCI IRQ, which can be INTA,INTB,INTC,INTD: + + ,-. + INTD--| | + |S| + INTC--|l| + |o| + INTB--|t| + |x| + INTA--| | + `-' + +These INTA-D PCI IRQs are always 'local to the card', their real meaning +depends on which slot they are in. If you look at the daisy chaining diagram, +a card in slot4, issuing INTA IRQ, it will end up as a signal on PIRQ2 of +the PCI chipset. Most cards issue INTA, this creates optimal distibution +between the PIRQ lines. (distributing IRQ sources properly is not a +necessity, PCI IRQs can be shared at will, but it's a good for performance +to have non shared interrupts). Slot5 should be used for videocards, they +dont use interrupts normally, thus they are not daisy chained either. + +so if you have your SCSI card (IRQ11) in Slot1, Tulip card (IRQ9) in +Slot2, then you'll have to specify this pirq= line: + + append="pirq=11,9" + +the following script tries to figure out such a default pirq= line from +your PCI configuration: + + echo -n pirq=; echo `scanpci | grep T_L | cut -c56-` | sed 's/ /,/g' + +note that this script wont work if you have skipped a few slots or if your +board does not do default daisy-chaining. (or the IO-APIC has the PIRQ pins +connected in some strange way). Eg. if in the above case you have your SCSI +card (IRQ11) in Slot3, and have Slot1 empty: + + append="pirq=0,9,11" + +[value '0' is a generic 'placeholder', reserved for empty (or non-IRQ emitting) +slots.] + +generally, it's always possible to find out the correct pirq= settings, just +permutate all IRQ numbers properly ... it will take some time though. An +'incorrect' pirq line will cause the booting process to hang, or a device +wont function properly (if it's inserted as eg. a module). + +If you have 2 PCI buses, then you can use up to 8 pirq values. Although such +boards tend to have a good configuration and will be included in the +whitelist. + +Be prepared that it might happen that you need some strange pirq line: + + append="pirq=0,0,0,0,0,0,9,11" + +use smart try-and-err techniques to find out the correct pirq line ... + + +the following pirq line can be used to force a board into the whitelist: + + append="pirq=0" + +[if your system works with no problems after this, then it should be added +to the official whitelist, contact us] + +good luck and mail to linux-smp@vger.rutgers.edu or +linux-kernel@vger.rutger.edu if you have any problems that are not covered +by this document. + +-- mingo + diff -ur --new-file old/linux/Documentation/binfmt_misc.txt new/linux/Documentation/binfmt_misc.txt --- old/linux/Documentation/binfmt_misc.txt Sun Aug 31 18:40:01 1997 +++ new/linux/Documentation/binfmt_misc.txt Sat Jan 24 01:40:13 1998 @@ -54,10 +54,10 @@ - enable support for packed DOS applications (pre-configured dosemu hdimages): echo ':DEXE:M::\x0eDEX::/usr/bin/dosexec:' > register -- enable support for DOS/Windows executables (using mzloader and dosemu/wine): - echo ':DOSWin:M::MZ::/usr/sbin/mzloader:' > register - echo ':DOScom:E::com::/usr/sbin/mzloader:' > register - echo ':DOSexe:E::exe::/usr/sbin/mzloader:' > register +- enable support for Windows executables using wine: + echo ':DOSWin:M::MZ::/usr/local/bin/wine:' > register + +For java support see Documentation/java.txt You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable) @@ -68,73 +68,12 @@ or /proc/sys/fs/binfmt_misc/status. -Emulating binfmt_java: -====================== - -To emulate binfmt_java the following register-strings could be used: -for compiled Java programs use - ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:' -for simple applet support use - ':Applet:E::html::/usr/local/java/bin/appletviewer:' -for more selective applet support (like binfmt_java) use - ':Applet:M:: in the first line to -let this work! - -For the compiled Java programs you need a wrapper script like the -following (this is because Java is broken in case of the filename -handling): - -====================== Cut here =================== -#!/bin/bash -# /usr/local/java/bin/javawrapper - the wrapper for binfmt_misc/java -CLASS=$1 - -# if classname is a link, we follow it (this could be done easier - how?) -if [ -L "$1" ] ; then - CLASS=`ls --color=no -l $1 | tr -s '\t ' ' ' | cut -d ' ' -f 11` -fi -CLASSN=`basename $CLASS .class` -CLASSP=`dirname $CLASS` - -FOO=$PATH -PATH=$CLASSPATH -if [ -z "`type -p -a $CLASSN.class`" ] ; then - # class is not in CLASSPATH - if [ -e "$CLASSP/$CLASSN.class" ] ; then - # append dir of class to CLASSPATH - if [ -z "${CLASSPATH}" ] ; then - export CLASSPATH=$CLASSP - else - export CLASSPATH=$CLASSP:$CLASSPATH - fi - else - # uh! now we would have to create a symbolic link - really - # ugly, i.e. print a message that one has to change the setup - echo "Hey! This is not a good setup to run $1 !" - exit 1 - fi -fi -PATH=$FOO - -shift -/usr/local/java/bin/java $CLASSN $@ -====================== Cut here =================== - -To add a Java program to your path best put a symbolic link to the main -.class file into /usr/bin (or another place you like) omitting the .class -extension. The directory containing the original .class file will be -added to your CLASSPATH during execution. - - - HINTS: ====== If you want to pass special arguments to your interpreter, you can -write a wrapper script for it. +write a wrapper script for it. See Documentation/java.txt for an +example. Your interpreter should NOT look in the PATH for the filename; the kernel passes it the full filename to use. Using the PATH can cause diff -ur --new-file old/linux/Documentation/cdrom/ide-cd new/linux/Documentation/cdrom/ide-cd --- old/linux/Documentation/cdrom/ide-cd Tue Dec 2 20:41:44 1997 +++ new/linux/Documentation/cdrom/ide-cd Wed Mar 18 06:39:11 1998 @@ -1,12 +1,12 @@ IDE-CD driver documentation -19 May 1996 -scott snyder +Originally by scott snyder (19 May 1996) +Carrying on the torch is: Erik Andersen 1. Introduction --------------- -The ide-cd driver should work with all ATAPI 1.2 compliant cdrom -drives which attach to an IDE interface. Note that some cdrom vendors +The ide-cd driver should work with all ATAPI ver 1.2 to ATAPI 2.6 compliant +cdrom drives which attach to an IDE interface. Note that some cdrom vendors (including Mitsumi, Sony, Creative, Aztech, and Goldstar) have made both ATAPI-compliant drives and drives which use a proprietary interface. If your drive uses one of those proprietary interfaces, @@ -28,9 +28,7 @@ - On drives which support it, reading digital audio data directly from audio tracks. The program cdda2wav can be used for this. - Note, however, that only a few drives actually support this - function; the only ones which i've heard of successes with are Sony - and Toshiba drives. + Note, however, that only some drives actually support this. - There is now support for cdrom changers which comply with the ATAPI 2.6 draft standard (such as the NEC CDR-251). This additional @@ -50,10 +48,13 @@ driver. 1. Make sure that the ide and ide-cd drivers are compiled into the - kernel you're using. When configuring the kernel, say `yes' to the - options + kernel you're using. When configuring the kernel, in the section + entitled "Floppy, IDE, and other block devices", say either `Y' + (which will compile the support directly into the kernel) or `M' + (to compile support as a module which can be loaded and unloaded) + to the options: - Enhanced IDE/MFM/RLL disk/cdrom/tape support + Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support Include IDE/ATAPI CDROM support and `no' to @@ -74,8 +75,8 @@ address and an IRQ number, the standard assignments being 0x170 and 14 for the primary interface and 0x1f0 and 15 for the secondary interface. Each interface can control up to two devices, - where each device can be either a hard drive, a cdrom drive, or a - tape drive. The two devices on an interface are called `master' + where each device can be a hard drive, a cdrom drive, a floppy drive, + or a tape drive. The two devices on an interface are called `master' and `slave'; this is usually selectable via a jumper on the drive. Linux names these devices as follows. The master and slave devices @@ -223,8 +224,8 @@ - If the autoprobing is not finding your drive, you can tell the driver to assume that one exists by using a lilo option of the form `hdX=cdrom', where X is the drive letter corresponding to - where your drive is installed (see section 2). Note that if you - do this and you see a boot message like + where your drive is installed. Note that if you do this and you + see a boot message like hdX: ATAPI cdrom (?) @@ -278,7 +279,16 @@ there are hardware problems with the interrupt setup; they apparently don't use interrupts. - + - If you own a Pioneer DR-A24X, you _will_ get nasty error messages + on boot such as "irq timeout: status=0x50 { DriveReady SeekComplete }" + The Pioneer DR-A24X cdrom drives are fairly popular these days. + Unfortunatly, these drives seem to become very confused when we perform + the standard Linux ATA disk drive probe. If you own one of these drives, + you can bypass the ATA probing which confuses these cdrom drives, by + adding `append="hdX=noprobe hdX=cdrom"' to your lilo.conf file and runing + lilo (again where X is the drive letter corresponding to where your drive + is installed.) + c. System hangups. - If the system locks up when you try to access the cdrom, the most diff -ur --new-file old/linux/Documentation/devices.tex new/linux/Documentation/devices.tex --- old/linux/Documentation/devices.tex Fri Dec 5 02:37:00 1997 +++ new/linux/Documentation/devices.tex Wed Feb 18 05:11:25 1998 @@ -4,7 +4,7 @@ % pages to print... :-) If you're actually putting this in print, you % may wish to change these. % -% $Id: devices.tex,v 1.4 1997/12/05 01:34:21 hpa Exp $ +% $Id: devices.tex,v 1.7 1998/02/18 04:07:45 hpa Exp $ % \oddsidemargin=0in \textwidth=6.5in @@ -50,7 +50,7 @@ % \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: December 4, 1997} +\date{Last revised: February 17, 1998} \maketitle % \noindent @@ -199,6 +199,7 @@ \major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices} \major{ }{}{block}{Reserved for parallel port ATAPI disk} \major{48}{}{char }{SDL RISCom serial card} +\major{48}{--55}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \major{49}{}{char }{SDL RISCom serial card -- alternate devices} \major{50}{}{char }{Reserved for GLINT} \major{51}{}{char }{Baycom radio modem} @@ -243,8 +244,10 @@ \major{93}{}{char }{IBM Smart Capture Card frame grabber} \major{94}{}{char }{miroVIDEO DC10/30 capture/playback device} \major{95}{}{char }{IP Filter} -\major{96}{}{char }{Reserved for parallel port ATAPI tape} -\major{97}{--119}{}{Unallocated} +\major{96}{}{char }{Parallel port ATAPI tape} +\major{97}{}{char }{Parallel port generic ATAPI interface} +\major{98}{}{char }{Control and Measurement Device (comedi)} +\major{99}{--119}{}{Unallocated} \major{120}{--127}{}{Local/experimental use} \major{128}{--239}{}{Unallocated} \major{240}{--254}{}{Local/experimental use} @@ -299,6 +302,11 @@ the position within the series. \end{itemize} +\noindent +In the future, it is likely that the PTY master multiplex ({\file +/dev/ptmx}) device will be used to acquire a PTY on demand. If so, +the actual PTY masters will be unnamed devices. + \begin{devicelist} \major{}{}{block}{Floppy disks} \minor{0}{/dev/fd0}{Controller 1, drive 1 autodetect} @@ -325,7 +333,7 @@ \minor{ 72}{/dev/fd?h1494}{5.25\tum\ 1494K in a 1200K drive} \minor{ 92}{/dev/fd?h1600}{5.25\tum\ 1600K in a 1200K drive\1} \minor{}{}{} - \minor{ 12}{/dev/fd?u360}{3.5\tum\ \num{4}{360}K Double Density} + \minor{ 12}{/dev/fd?u360}{3.5\tum\ \num{4}{360}K Double Density\2} \minor{ 16}{/dev/fd?u720}{3.5\tum\ \num{4}{720}K Double Density\1} \minor{120}{/dev/fd?u800}{3.5\tum\ \num{4}{800}K Double Density\2} \minor{ 52}{/dev/fd?u820}{3.5\tum\ \num{4}{820}K Double Density} @@ -366,7 +374,13 @@ \minor{1}{/dev/ttyp1}{Second PTY slave} \minordots \minor{255}{/dev/ttyef}{256th PTY slave} -\\ +\end{devicelist} + +\noindent +In the future, Linux may adopt the Unix98 naming scheme {\file +/dev/pts/0}, {\file /dev/pts/1}, ... + +\begin{devicelist} \major{}{}{block}{First MFM, RLL and IDE hard disk/CD-ROM interface} \minor{0}{/dev/hda}{Master: whole disk (or CD-ROM)} \minor{64}{/dev/hdb}{Slave: whole disk (or CD-ROM)} @@ -412,6 +426,7 @@ \major{ 5}{}{char }{Alternate TTY devices} \minor{0}{/dev/tty}{Current TTY device} \minor{1}{/dev/console}{System console} + \minor{2}{/dev/ptmx}{PTY master multiplex} \minor{64}{/dev/cua0}{Callout device corresponding to {\file ttyS0}} \minordots \minor{127}{/dev/cua63}{Callout device corresponding to {\file ttyS63}} @@ -1087,8 +1102,10 @@ \end{devicelist} \noindent -Partitions are handled the same way as for IDE disks (see major number -3). +This device is obsolete and will be removed in a future version of +Linux. It has been replaced with the parallel port IDE disk driver at +major number 45. Partitions are handled the same way as for IDE disks +(see major number 3). \begin{devicelist} \major{41}{}{char }{Yet Another Micro Monitor} @@ -1098,6 +1115,11 @@ \minor{0}{/dev/bpcd}{BackPack CD-ROM} \end{devicelist} +\noindent +This device is obsolete and will be removed in a future version of +Linux. It has been replaced with the parallel port ATAPI CD-ROM +driver at major number 46. + \begin{devicelist} \major{42}{}{}{Demo/sample use} \end{devicelist} @@ -1163,13 +1185,30 @@ \minordots \minor{191}{/dev/ippp63}{64th SyncPPP device} \minor{255}{/dev/isdninfo}{ISDN monitor interface} +\\ +\major{ }{}{block}{Parallel port IDE disk devices} + \minor{0}{/dev/pda}{First parallel port IDE disk} + \minor{16}{/dev/pdb}{Second parallel port IDE disk} + \minor{32}{/dev/pdc}{Third parallel port IDE disk} + \minor{48}{/dev/pdd}{Fourth parallel port IDE disk} \end{devicelist} +\noindent +Partitions are handled in the same way as for IDE disks (see major +number 3) except that the partition limit is 15 rather than 63 per +disk. + \begin{devicelist} \major{46}{}{char }{Comtrol Rocketport serial card} \minor{0}{/dev/ttyR0}{First Rocketport port} \minor{1}{/dev/ttyR1}{Second Rocketport port} \minordots +\\ +\major{ }{}{block}{Parallel port ATAPI CD-ROM devices} + \minor{0}{/dev/pcd0}{First parallel port ATAPI CD-ROM} + \minor{1}{/dev/pcd1}{Second parallel port ATAPI CD-ROM} + \minor{2}{/dev/pcd2}{Third parallel port ATAPI CD-ROM} + \minor{3}{/dev/pcd3}{Fourth parallel port ATAPI CD-ROM} \end{devicelist} \begin{devicelist} @@ -1177,13 +1216,25 @@ \minor{0}{/dev/cur0}{Callout device corresponding to {\file ttyR0}} \minor{1}{/dev/cur1}{Callout device corresponding to {\file ttyR1}} \minordots +\\ +\major{ }{}{block}{Parallel port ATAPI disk devices} + \minor{0}{/dev/pf0}{First parallel port ATAPI disk} + \minor{1}{/dev/pf1}{Second parallel port ATAPI disk} + \minor{2}{/dev/pf2}{Third parallel port ATAPI disk} + \minor{3}{/dev/pf3}{Fourth parallel port ATAPI disk} \end{devicelist} +\noindent +This driver is intended for floppy disks and similar devices and hence +does not support partitioning. + \begin{devicelist} \major{48}{}{char }{SDL RISCom serial card} \minor{0}{/dev/ttyL0}{First RISCom port} \minor{1}{/dev/ttyL1}{Second RISCom port} \minordots +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1191,10 +1242,14 @@ \minor{0}{/dev/cul0}{Callout device corresponding to {\file ttyL0}} \minor{1}{/dev/cul1}{Callout device corresponding to {\file ttyL1}} \minordots +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} \major{50}{}{char}{Reserved for GLINT} +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1202,6 +1257,8 @@ \minor{0}{/dev/bc0}{First Baycom radio modem} \minor{1}{/dev/bc1}{Second Baycom radio modem} \minordots +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1210,6 +1267,8 @@ \minor{1}{/dev/dcbri1}{Second DataComm card} \minor{2}{/dev/dcbri2}{Third DataComm card} \minor{3}{/dev/dcbri3}{Fourth DataComm card} +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1230,6 +1289,10 @@ commercial interface by P\&E. \begin{devicelist} +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} +\end{devicelist} + +\begin{devicelist} \major{54}{}{char }{Electrocardiognosis Holter serial card} \minor{0}{/dev/holter0}{First Holter port} \minor{1}{/dev/holter1}{Second Holter port} @@ -1242,8 +1305,14 @@ heart monitoring equipment. \begin{devicelist} +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} +\end{devicelist} + +\begin{devicelist} \major{55}{}{char }{DSP56001 digital signal processor} \minor{0}{/dev/dsp56k}{First DSP56001} +\\ +\major{ }{}{block}{Reserved for Mylex DAC960 PCI RAID Controller} \end{devicelist} \begin{devicelist} @@ -1582,7 +1651,41 @@ \end{devicelist} \begin{devicelist} -\major{96}{--119}{}{Unallocated} +\major{96}{}{char }{Parallel port ATAPI tape devices} + \minor{0}{/dev/pt0}{First parallel port ATAPI tape} + \minor{1}{/dev/pt1}{Second parallel port ATAPI tape} + \minor{2}{/dev/pt2}{Third parallel port ATAPI tape} + \minor{3}{/dev/pt3}{Fourth parallel port ATAPI tape} + \minor{128}{/dev/npt0}{First parallel port ATAPI tape, no rewind} + \minor{129}{/dev/npt1}{Second parallel port ATAPI tape, no rewind} + \minor{130}{/dev/npt2}{Third parallel port ATAPI tape, no rewind} + \minor{131}{/dev/npt3}{Fourth parallel port ATAPI tape, no rewind} +\end{devicelist} + +\begin{devicelist} +\major{97}{}{char }{Parallel port generic ATAPI interface} + \minor{0}{/dev/pg0}{First parallel port ATAPI device} + \minor{1}{/dev/pg1}{Second parallel port ATAPI device} + \minor{2}{/dev/pg2}{Third parallel port ATAPI device} + \minor{3}{/dev/pg3}{Fourth parallel port ATAPI device} +\end{devicelist} + +\noindent +These devices support the same API as the generic SCSI devices. + +\begin{devicelist} +\major{98}{}{char }{Control and Mesurement Device (comedi)} + \minor{0}{/dev/comedi0}{First comedi device} + \minor{1}{/dev/comedi1}{Second comedi device} + \minordots +\end{devicelist} + +\noindent +See {\url http://stm.lbl.gov/comedi/} or {\url +http://www.llp.fu-berlin.de/}. + +\begin{devicelist} +\major{99}{--119}{}{Unallocated} \end{devicelist} \begin{devicelist} diff -ur --new-file old/linux/Documentation/devices.txt new/linux/Documentation/devices.txt --- old/linux/Documentation/devices.txt Sun Jan 4 19:40:15 1998 +++ new/linux/Documentation/devices.txt Wed Feb 18 05:11:25 1998 @@ -1,7 +1,7 @@ LINUX ALLOCATED DEVICES Maintained by H. Peter Anvin - Last revised: December 4, 1997 + Last revised: February 17, 1998 This list is the Linux Device List, the official registry of allocated device numbers and /dev directory nodes for the Linux operating @@ -91,16 +91,17 @@ the 1st through 16th series of 16 pseudo-ttys each, and * the fifth letter is one of 0123456789abcdef indicating the position within the series. + + In the future, it is likely that the PTY master + multiplex (/dev/ptmx) device will be used to acquire a + PTY on demand. If so, the actual PTY masters will be + unnamed devices. block Floppy disks - 0 = /dev/fd0 Controller 1, drive 1 autodetect - 1 = /dev/fd1 Controller 1, drive 2 autodetect - 2 = /dev/fd2 Controller 1, drive 3 autodetect - 3 = /dev/fd3 Controller 1, drive 4 autodetect - 128 = /dev/fd4 Controller 2, drive 1 autodetect - 129 = /dev/fd5 Controller 2, drive 2 autodetect - 130 = /dev/fd6 Controller 2, drive 3 autodetect - 131 = /dev/fd7 Controller 2, drive 4 autodetect + 0 = /dev/fd0 First floppy disk autodetect + 1 = /dev/fd1 Second floppy disk autodetect + 2 = /dev/fd2 Third floppy disk autodetect + 3 = /dev/fd3 Fourth floppy disk autodetect To specify format, add to the autodetect device number: 0 = /dev/fd? Autodetect format @@ -116,9 +117,10 @@ 72 = /dev/fd?h1494 5.25" 1494K in a 1200K drive 92 = /dev/fd?h1600 5.25" 1600K in a 1200K drive(1) - 12 = /dev/fd?u360 3.5" 360K Double Density - 120 = /dev/fd?u800 3.5" 800K Double Density(1) - 52 = /dev/fd?u820 3.5" 820K Double Density(2) + 12 = /dev/fd?u360 3.5" 360K Double Density(2) + 16 = /dev/fd?u720 3.5" 720K Double Density(1) + 120 = /dev/fd?u800 3.5" 800K Double Density(2) + 52 = /dev/fd?u820 3.5" 820K Double Density 68 = /dev/fd?u830 3.5" 830K Double Density 84 = /dev/fd?u1040 3.5" 1040K Double Density(1) 88 = /dev/fd?u1120 3.5" 1120K Double Density(1) @@ -152,12 +154,15 @@ 0 = /dev/ttyp0 First PTY slave 1 = /dev/ttyp1 Second PTY slave ... - 256 = /dev/ttyef 256th PTY slave + 255 = /dev/ttyef 256th PTY slave + + In the future, Linux may adopt the Unix98 naming + scheme (/dev/pts/0, /dev/pts/1, ...) block First MFM, RLL and IDE hard disk/CD-ROM interface 0 = /dev/hda Master: whole disk (or CD-ROM) 64 = /dev/hdb Slave: whole disk (or CD-ROM) - + For partitions, add to the whole disk device number: 0 = /dev/hd? Whole disk 1 = /dev/hd?1 First partition @@ -169,7 +174,7 @@ partitions, and 5 and above are logical partitions. Other versions of Linux use partitioning schemes appropriate to their respective architectures. - + 4 char TTY devices 0 = /dev/tty0 Current virtual console @@ -196,6 +201,7 @@ 5 char Alternate TTY devices 0 = /dev/tty Current TTY device 1 = /dev/console System console + 2 = /dev/ptmx PTY master multiplex 64 = /dev/cua0 Callout device corresponding to ttyS0 ... 127 = /dev/cua63 Callout device corresponding to ttyS63 @@ -742,6 +748,9 @@ block Syquest EZ135 parallel port removable drive 0 = /dev/eza Parallel EZ135 drive, whole disk + This device is obsolete and will be removed in a + future version of Linux. It has been replaced with + the parallel port IDE disk driver at major number 45. Partitions are handled in the same way as IDE disks (see major number 3). @@ -750,6 +759,10 @@ block MicroSolutions BackPack parallel port CD-ROM 0 = /dev/bpcd BackPack CD-ROM + This device is obsolete and will be removed in a + future version of Linux. It has been replaced with + the parallel port ATAPI CD-ROM driver at major number 46. + 42 Demo/sample use This number is intended for use in sample code, as @@ -807,39 +820,66 @@ 191 = /dev/ippp63 64th SyncPPP device 255 = /dev/isdninfo ISDN monitor interface + block Parallel port IDE disk devices + 0 = /dev/pda First parallel port IDE disk + 16 = /dev/pdb Second parallel port IDE disk + 32 = /dev/pdc Third parallel port IDE disk + 48 = /dev/pdd Fourth parallel port IDE disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the partition + limit is 15 rather than 63 per disk. 46 char Comtrol Rocketport serial card 0 = /dev/ttyR0 First Rocketport port 1 = /dev/ttyR1 Second Rocketport port ... + block Parallel port ATAPI CD-ROM devices + 0 = /dev/pcd0 First parallel port ATAPI CD-ROM + 1 = /dev/pcd1 Second parallel port ATAPI CD-ROM + 2 = /dev/pcd2 Third parallel port ATAPI CD-ROM + 3 = /dev/pcd3 Fourth parallel port ATAPI CD-ROM 47 char Comtrol Rocketport serial card - alternate devices 0 = /dev/cur0 Callout device corresponding to ttyR0 1 = /dev/cur1 Callout device corresponding to ttyR1 ... + block Parallel port ATAPI disk devices + 0 = /dev/pf0 First parallel port ATAPI disk + 1 = /dev/pf1 Second parallel port ATAPI disk + 2 = /dev/pf2 Third parallel port ATAPI disk + 3 = /dev/pf3 Fourth parallel port ATAPI disk + + This driver is intended for floppy disks and similar + devices and hence does not support partitioning. 48 char SDL RISCom serial card 0 = /dev/ttyL0 First RISCom port 1 = /dev/ttyL1 Second RISCom port ... + block Reserved for Mylex DAC960 PCI RAID controller 49 char SDL RISCom serial card - alternate devices 0 = /dev/cul0 Callout device corresponding to ttyL0 1 = /dev/cul1 Callout device corresponding to ttyL1 ... + block Reserved for Mylex DAC960 PCI RAID controller 50 char Reserved for GLINT + block Reserved for Mylex DAC960 PCI RAID controller 51 char Baycom radio modem 0 = /dev/bc0 First Baycom radio modem 1 = /dev/bc1 Second Baycom radio modem ... + block Reserved for Mylex DAC960 PCI RAID controller 52 char Spellcaster DataComm/BRI ISDN card 0 = /dev/dcbri0 First DataComm card 1 = /dev/dcbri1 Second DataComm card 2 = /dev/dcbri2 Third DataComm card 3 = /dev/dcbri3 Fourth DataComm card + block Reserved for Mylex DAC960 PCI RAID controller 53 char BDM interface for remote debugging MC683xx microcontrollers 0 = /dev/pd_bdm0 PD BDM interface on lp0 @@ -855,6 +895,8 @@ Domain Interface and ICD is the commercial interface by P&E. + block Reserved for Mylex DAC960 PCI RAID controller + 54 char Electrocardiognosis Holter serial card 0 = /dev/holter0 First Holter port 1 = /dev/holter1 Second Holter port @@ -864,8 +906,11 @@ to transfer data from Holter 24-hour heart monitoring equipment. + block Reserved for Mylex DAC960 PCI RAID controller + 55 char DSP56001 digital signal processor 0 = /dev/dsp56k First DSP56001 + block Reserved for Mylex DAC960 PCI RAID controller 56 char Apple Desktop Bus 0 = /dev/adb ADB bus control @@ -1120,7 +1165,33 @@ 2 = /dev/ipstate State information log file 3 = /dev/ipauth Authentication control device/log file - 96-119 UNALLOCATED + 96 char Parallel port ATAPI tape devices + 0 = /dev/pt0 First parallel port ATAPI tape + 1 = /dev/pt1 Second parallel port ATAPI tape + 2 = /dev/pt2 Third parallel port ATAPI tape + 3 = /dev/pt3 Fourth parallel port ATAPI tape + 128 = /dev/npt0 First p.p. ATAPI tape, no rewind + 129 = /dev/npt1 Second p.p. ATAPI tape, no rewind + 130 = /dev/npt2 Third p.p. ATAPI tape, no rewind + 131 = /dev/npt3 Fourth p.p. ATAPI tape, no rewind + + 97 char Parallel port generic ATAPI interface + 0 = /dev/pg0 First parallel port ATAPI device + 1 = /dev/pg1 Second parallel port ATAPI device + 2 = /dev/pg2 Third parallel port ATAPI device + 3 = /dev/pg3 Fourth parallel port ATAPI device + + These devices support the same API as the generic SCSI + devices. + + 98 char Control and Measurement Device (comedi) + 0 = /dev/comedi0 First comedi device + 1 = /dev/comedi1 Second comedi device + ... + + See http://stm.lbl.gov/comedi or http://www.llp.fu-berlin.de/. + + 99-119 UNALLOCATED 120-127 LOCAL/EXPERIMENTAL USE diff -ur --new-file old/linux/Documentation/digiboard.txt new/linux/Documentation/digiboard.txt --- old/linux/Documentation/digiboard.txt Sun Apr 13 19:18:20 1997 +++ new/linux/Documentation/digiboard.txt Fri Jan 30 22:52:57 1998 @@ -254,3 +254,35 @@ ;; par[0-2]) ----- End Makedev patch + +----------------------------------------------------------------------------- + +Changes v1.5.5: + +The ability to use the kernel's command line to pass in the configuration for +boards. Using LILO's APPEND command, a string of comma separated identifiers +or integers can be used. The 6 values in order are: + + Enable/Disable this card, + Type of card: PC/Xi(0), PC/Xe(1), PC/Xeve(2), PC/Xem(3) + Enable/Disable alternate pin arrangement, + Number of ports on this card, + I/O Port where card is configured (in HEX if using string identifiers), + Base of memory window (in HEX if using string identifiers), + +Samples: + append="digi=E,PC/Xi,D,16,200,D0000" + append="digi=1,0,0,16,512,(whatever D0000 is in base 10 :) + +Driver's minor device numbers are conserved. This means that instead of +each board getting a block of 16 minors pre-assigned, it gets however +many it should, with the next card following directly behind it. A +system with 4 2-port PC/Xi boards will use minor numbers 0-7. +This conserves some memory, and removes a few hard coded constants. + +NOTE!! NOTE!! NOTE!! +The definition of PC/Xem as a valid board type is the BEGINNING of support +for this device. The driver does not currently recognise the board, nor +does it want to initialize it. At least not the EISA version. + +Mike McLagan 5, April 1996. diff -ur --new-file old/linux/Documentation/filesystems/affs.txt new/linux/Documentation/filesystems/affs.txt --- old/linux/Documentation/filesystems/affs.txt Wed Dec 3 07:25:07 1997 +++ new/linux/Documentation/filesystems/affs.txt Tue Feb 24 07:01:26 1998 @@ -65,6 +65,11 @@ verbose The volume name, file system type and block size will be written to the syslog when the filesystem is mounted. +mufs The filesystem is really a muFS, also it doesn't + identify itself as one. This option is neccessary if + the filesystem wasn't formatted as muFS, but is used + as one. + prefix=path Path will be prefixed to every absolute path name of symbolic links on an AFFS partition. Default = / diff -ur --new-file old/linux/Documentation/filesystems/coda.txt new/linux/Documentation/filesystems/coda.txt --- old/linux/Documentation/filesystems/coda.txt Sun Dec 21 23:45:14 1997 +++ new/linux/Documentation/filesystems/coda.txt Thu Mar 5 00:14:32 1998 @@ -1,3 +1,27 @@ + +NOTE: +This is one of the technical documents describing a component of +Coda -- this document describes the client kernel-Venus interface. + +For more information: + http://www.coda.cs.cmu.edu +For user level software needed to run Coda: + ftp://ftp.coda.cs.cmu.edu + +To run Coda you need to get a user level cache manager for the client, +named Venus, as well as tools to manipulate ACL's, to log in etc. The +client needs to have the Coda filesystem selected in the kernel +configuration. + +The server needs a user level server and at present does not depend on +kernel support. + + + + + + + The Venus kernel interface Peter J. Braam v1.0, Nov 9, 1997 diff -ur --new-file old/linux/Documentation/filesystems/isofs.txt new/linux/Documentation/filesystems/isofs.txt --- old/linux/Documentation/filesystems/isofs.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/filesystems/isofs.txt Tue Feb 10 01:12:54 1998 @@ -0,0 +1,28 @@ +Mount options that are the same as for msdos and vfat partitions. + + gid=nnn All files in the partition will be in group nnn. + uid=nnn All files in the partition will be owned by user id nnn. + umask=nnn The permission mask (see umask(1)) for the partition. + +Mount options that are the same as vfat partitions. These are only useful +when using discs encoded using Microsoft's Joliet extensions. + iocharset=name Character set to use for converting from Unicode to + ASCII. Joliet filenames are stored in Unicode format, but + Unix for the most part doesn't know how to deal with Unicode. + There is also an option of doing UTF8 translations with the + utf8 option. + utf8 Encode Unicode names in UTF8 format. Default is no. + +Mount options that are unique to the isofs filesystem. + block=512 Set the block size for the disk to 512 bytes + block=1024 Set the block size for the disk to 1024 bytes + block=2048 Set the block size for the disk to 2048 bytes + check=relaxed Matches filenames with different cases + check=strict Matches only filenames with the exact same case + cruft Try to handle badly formatted CDs. + map=off Do not map non-rockridge filenames to lowercase + map=normal Map rockridge filenames to lowercase + mode=xxx Sets the permissions on files to xxx + nojoliet Ignore Joliet extensions if they are present. + norock Ignore rockridge extensions if they are present. + unhide Show hidden files. diff -ur --new-file old/linux/Documentation/filesystems/smbfs.txt new/linux/Documentation/filesystems/smbfs.txt --- old/linux/Documentation/filesystems/smbfs.txt Mon Nov 24 19:30:40 1997 +++ new/linux/Documentation/filesystems/smbfs.txt Wed Jan 21 19:09:31 1998 @@ -1,27 +1,20 @@ 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 +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. 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. -To use smbfs, you need to install the Samba package (Samba-1.9.17p1 or -later), and you need the special mount program from the smbfs package -(smbfs-2.1.0 or later), found on - - ftp://ftp.gwdg.de/pub/linux/misc/smbfs/dontuse - -After downloading the smbfs package, apply the patch to the smbclient -program and recompile. Smbfs can then be mounted from the smbclient -command line, as for example: - - smb: \>mount /mnt/tmp -f 755 - -For convenience, you may wish to package the command in a script like this: - -#!/bin/sh -echo "mount /mnt/tmp -f 755" | smbclient //server/c$ -U administrator% +To use smbfs, you must first install the Samba package (Samba-1.9.18p1 or +later). This package includes the special smbmount utility needed to mount +smbfs volumes. Refer to the smbmount(8) and smbmnt(8) manpages for the +details regarding smbfs mounts. + +The smbmount utility reads the Samba smb.conf config file for some of its +options, and at least one of these is important for smbfs operation. You +should enable the TCP_NODELAY socket option, or else directory listings +will be dramatically slower (under Win NT at least). Mount-Time Options Windows 95 has several bugs that affect SMB operations, and smbfs includes @@ -37,11 +30,12 @@ Option Value Effect Identify Win 95 Server 1 Enables bug fixes Use Core Attributes 2 Speeds up directory scans, only mtime +Use Dir Attributes 4 Alternate way to get file attributes To apply the options, sum the values and prepend it to the file mode. For -example, to use both options with file mode 755, you would prepend 3 to 755: +example, to use options 1 and 2 with file mode 755, you would specify 3755: - cnt>mount /mnt/tmp -f 3755 + mount /mnt/tmp -f 3755 Smbfs will print a message at mount time confirming the selected options. Note that _only_ Windows 95 servers require special treatment; using the diff -ur --new-file old/linux/Documentation/filesystems/vfs.txt new/linux/Documentation/filesystems/vfs.txt --- old/linux/Documentation/filesystems/vfs.txt Sun Feb 2 14:18:29 1997 +++ new/linux/Documentation/filesystems/vfs.txt Wed Feb 25 07:08:00 1998 @@ -8,7 +8,7 @@ The VFS relatively simple, but it is nice not to have to browse through pages of code to determine what is expected when writing a filesystem. Hopefully this helps anyone attempting such a feat, as well as clearing up -a few important points/dependancies. +a few important points/dependencies. register_filesystem (struct file_system_type *fstype) diff -ur --new-file old/linux/Documentation/hayes-esp.txt new/linux/Documentation/hayes-esp.txt --- old/linux/Documentation/hayes-esp.txt Tue Aug 12 01:57:59 1997 +++ new/linux/Documentation/hayes-esp.txt Fri Feb 13 00:47:44 1998 @@ -1,14 +1,37 @@ -HAYES ESP DRIVER VERSION 1.6 +HAYES ESP DRIVER VERSION 2.0 + +A big thanks to the people at Hayes, especially Alan Adamson. Their support +has enabled me to provide enhancements to the driver. + +Please report your experiences with this driver to me (arobinso@nyx.net). I +am looking for both positive and negative feedback. + +*** IMPORTANT CHANGES FOR 2.0 *** +Support for PIO mode. Five situations will cause PIO mode to be used: +1) A multiport card is detected. PIO mode will always be used. (8 port cards +do not support DMA). +2) The DMA channel is set to an invalid value (anything other than 1 or 3). +3) The DMA buffer/channel could not be allocated. The port will revert to PIO +mode until it is reopened. +4) Less than 33 bytes need to be transferred to/from the FIFOs. PIO mode will +be used for that transfer only. +5) A port needs to do a DMA transfer and another port is already using the +DMA channel. PIO mode will be used for that transfer only. + +A patch for setserial (2.12) is included to allow the ESP enhanced mode +configuration to be viewed and changed. +*** + +This package contains the files needed to compile a module to support the Hayes +ESP card. The drivers are basically a modified version of the serial drivers. Features: - Uses the enhanced mode of the ESP card, allowing a wider range of interrupts and features than compatibilty mode -- Uses DMA to transfer data to and from the ESP's FIFOs, reducing CPU load +- Uses DMA and 16 bit PIO mode to transfer data to and from the ESP's FIFOs, + reducing CPU load - Supports primary and secondary ports -- Special version of setserial can be used to view/change the enhanced mode - configuration. The setserial patch is distributed with the standalone - driver distribution. See http://www.nyx.net/~arobinso for more information. To compile/install: @@ -47,7 +70,8 @@ insmod esp divisor=0,0,0,0,0,0,0x84,0 The dma= option can be used to set the DMA channel. The channel can be either -1 or 3. For example, to set the dma channel to 3, the insmod command would be: +1 or 3. Specifying any other value will force the driver to use PIO mode. +For example, to set the dma channel to 3, the insmod command would be: insmod esp dma=3 diff -ur --new-file old/linux/Documentation/ioctl-number.txt new/linux/Documentation/ioctl-number.txt --- old/linux/Documentation/ioctl-number.txt Tue Dec 2 20:41:44 1997 +++ new/linux/Documentation/ioctl-number.txt Sat Feb 21 02:54:35 1998 @@ -1,5 +1,5 @@ Ioctl Numbers -1 Sep 1997 +18 Feb 1998 Michael Chastain @@ -86,7 +86,7 @@ 'W' 28-2F linux/iso16-relay.h in development 'Y' all linux/cyclades.h 'a' all various, see http://lrcwww.epfl.ch/linux-atm/magic.html -'b' 00-3F bit3 vme host bridge in development: +'b' 00-FF bit3 vme host bridge in development: 'c' all linux/comstats.h 'f' all linux/ext2_fs.h @@ -99,6 +99,8 @@ 'n' all linux/ncp_fs.h 'p' 00-3F linux/mc146818rtc.h 'p' 40-7F linux/nvram.h +'p' 80-9F user-space parport in development: + 'r' all linux/msdos_fs.h 's' all linux/cdk.h 't' 00-7F linux/if_ppp.h @@ -108,6 +110,8 @@ 'w' all CERN SCI driver in development 'z' 00-3F CAN bus card in development: +'z' 40-7F CAN bas card in development: + 0x89 00-0F asm-i386/sockios.h 0x89 10-DF linux/sockios.h 0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range diff -ur --new-file old/linux/Documentation/isdn/README new/linux/Documentation/isdn/README --- old/linux/Documentation/isdn/README Fri May 30 06:53:03 1997 +++ new/linux/Documentation/isdn/README Wed Feb 25 07:08:00 1998 @@ -285,7 +285,7 @@ 5. Application a) For some card-types, firmware has to be loaded into the cards, before - proceeding with device-independant setup. See README. + proceeding with device-independent setup. See README. for how to do that. b) If you only intend to use ttys, you are nearly ready now. diff -ur --new-file old/linux/Documentation/java.txt new/linux/Documentation/java.txt --- old/linux/Documentation/java.txt Thu Nov 21 10:00:33 1996 +++ new/linux/Documentation/java.txt Sat Jan 24 01:40:13 1998 @@ -4,45 +4,92 @@ Linux beats them ALL! While all other OS's are TALKING about direct support of Java Binaries in the OS, Linux is doing it! -You execute Java classes as you would any other executable, after a few -small details: +You can execute Java applications and Java Applets just like any +other program after you have done the following: + +1) You MUST FIRST install the Java Developers Kit for Linux. + The Java on Linux HOWTO gives the details on getting and + installing this. This HOWTO can be found at: + + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Java-HOWTO + + You should also set up a reasonable CLASSPATH environment + variable to use Java applications that make use of any + nonstandard classes (not included in the same directory + as the application itself). + +2) You have to compile BINFMT_MISC either as module or into + the kernel (CONFIG_BINFMT_MISC) and set it up properly. + If you choose to compile it as a module, you will have + to insert it manually with modprobe/insmod, as kerneld + can not easy be supported with binfmt_misc. + Read the file 'binfmt_misc.txt' in this directory to know + more about the configuration process. + +3) Add the following configuration items to binfmt_misc + (you should really have read binfmt_misc.txt now): + support for Java applications: + ':Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/javawrapper:' + support for Java Applets: + ':Applet:E::html::/usr/local/java/bin/appletviewer:' + or the following, if you want to be more selective: + ':Applet:M:: in the first line + ('<' has to be the first character!) to let this work! + + For the compiled Java programs you need a wrapper script like the + following (this is because Java is broken in case of the filename + handling), again fix the path names, both in the script and in the + above given configuration string: + +====================== Cut here =================== +#!/bin/bash +# /usr/local/java/bin/javawrapper - the wrapper for binfmt_misc/java +CLASS=$1 + +# if classname is a link, we follow it (this could be done easier - how?) +if [ -L "$1" ] ; then + CLASS=`ls --color=no -l $1 | tr -s '\t ' ' ' | cut -d ' ' -f 11` +fi +CLASSN=`basename $CLASS .class` +CLASSP=`dirname $CLASS` + +FOO=$PATH +PATH=$CLASSPATH +if [ -z "`type -p -a $CLASSN.class`" ] ; then + # class is not in CLASSPATH + if [ -e "$CLASSP/$CLASSN.class" ] ; then + # append dir of class to CLASSPATH + if [ -z "${CLASSPATH}" ] ; then + export CLASSPATH=$CLASSP + else + export CLASSPATH=$CLASSP:$CLASSPATH + fi + else + # uh! now we would have to create a symbolic link - really + # ugly, i.e. print a message that one has to change the setup + echo "Hey! This is not a good setup to run $1 !" + exit 1 + fi +fi +PATH=$FOO + +shift +/usr/local/java/bin/java $CLASSN "$@" +====================== Cut here =================== + + +Now simply chmod +x the .class and/or .html files you want to execute. +To add a Java program to your path best put a symbolic link to the main +.class file into /usr/bin (or another place you like) omitting the .class +extension. The directory containing the original .class file will be +added to your CLASSPATH during execution. - 1) You MUST FIRST install the Java Developers Kit for Linux. - The Java on Linux HOWTO gives the details on getting and - installing this. This HOWTO can be found at: - - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Java-HOWTO - - If you install the JDK in a location other than /usr/bin/java, - then you will need to tell the kernel where you put the Java - interpreter. - There are two ways to do this. - One, edit fs/binfmt_java.c file and make the needed change to - the _PATH_JAVA definition at the top of that file. - Two, as root, issue the command: - echo "/path/to/java/interpreter" > /proc/sys/kernel/java-interpreter - (Currently, this does not work if you're using a module for - Java support.) - - 2) You must chmod the '*.class' files you wish to execute with - the execute bit. This is not normally (till now) done with - '.class' files. - - 3) You must optionally export a CLASSPATH environment variable, - if you plan to use Java applications installed outside of - /usr/local/java/classes/*. - - 4) Either compile your kernel with Java support builtin, or - as a loadable module. If a module, load it with insmod or - kerneld. - - 5) A caveat. When executing a java file, the java interpreter is - invoked only with the class name, not with the complete file path. - Therefore it is possible that the file the shell finds with PATH - is not the same file the java interpreter finds with CLASSPATH. - The recommended solution is to make symbolic links from a directory - in PATH to the actual class file in CLASSPATH, e.g., - /usr/local/bin/myapp -> /usr/local/java/classes/myapp.class. To test your new setup, enter in the following simple Java app, and name it "HelloWorld.java": @@ -53,59 +100,20 @@ } } - Now compile the application with: - - /usr/local/java/bin/javac HelloWorld.java + javac HelloWorld.java Set the executable permissions of the binary file, with: - chmod 755 HelloWorld.class And then execute it: - ./HelloWorld.class -Yes, it's JUST THAT EASY! ;-) - ------------------------------------------------------------------ - -Nope, I didn't forget about Java Applets! ;-) - -While this may not be the best way to do this, it works! - -Take any html file used with the Java appletviewer (like the -demo/Blink/example1.html file), and: - - 1) Insert a new first line of: - - - - Make sure the '<' is the first character in the file. This - will be treated as a valid HTML comment outside of this - Java Applet support, so the modified file can still be used - with all known browsers. - - 2) If you install the applet viewer in a location other than - /usr/bin/appletviewer, then you will need to tell the - kernel where you put the Java appletviewer. - There are two ways to do this. - One, edit fs/binfmt_java.c file and make the needed change to - the _PATH_APPLET definition at the top of that file. - Two, as root, issue the command: - echo "/path/to/java/appletviewer" > /proc/sys/kernel/java-appletviewer - (Currently, this does not work if you're using a module for - Java support.) - - 3) You must chmod the '*.html' files you wish to execute with - the execute bit. This is not normally (till now) done with - '.html' files. - - 4) And then execute it. - +To execute Java Applets, simple chmod the *.html files to include +the execution bit, then just do + ./Applet.html -Brian A. Lantz -brian@lantz.com -(/proc/sys/kernel/java-* support by Mike Shaver (shaver@ingenia.com)) +originally by Brian A. Lantz, brian@lantz.com +heavily edited for binfmt_misc by Richard Günther. diff -ur --new-file old/linux/Documentation/kmod.txt new/linux/Documentation/kmod.txt --- old/linux/Documentation/kmod.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/kmod.txt Tue Mar 10 23:43:13 1998 @@ -0,0 +1,47 @@ +Kmod: The Kernel Module Loader +Kirk Petersen + +Kmod is a simple replacement for kerneld. It consists of a +request_module() replacement and a kernel thread called kmod. When the +kernel requests a module, the kmod wakes up and execve()s modprobe, +passing it the name that was requested. After a configurable period of +time, kmod will have delete_module() remove any unused modules. + +Kmod is configurable through two entries in /proc/sys/kernel. You can +set the path of modprobe (where the kernel looks for it) by doing: + + echo "/sbin/modprobe" > /proc/sys/kernel/modprobe + +To tell kmod when to unload unused modules, do something like: + + echo "120" > /proc/sys/kernel/kmod_unload_delay + +Kmod only loads and unloads modules. Kerneld could do more (although +nothing in the standard kernel used its other features). If you +require features such as request_route, we suggest that you take +a similar approach. A simple request_route function could be called, +and a kroute kernel thread could be sent off to do the work. But +we should probably keep this to a minimum. + +Kerneld also had a mechanism for storing device driver settings. This +can easily be done with modprobe. When a module is unloaded, modprobe +could look at a per-driver-configurable location (/proc/sys/drivers/blah) +for device driver settings and save them to a file. When a module +is loaded, simply cat that file back to that location in the proc +filesystem. Or perhaps a script could be a setting in /etc/modules.conf. +There are many user-land methods that will work (I prefer using /proc, +myself). + +If kerneld worked, why replace it? + +- kerneld used sysv ipc, which can now be made into a module. Besides, + sysv ipc is ugly and should therefore be avoided (well, certainly for + kernel level stuff) + +- both kmod and kerneld end up doing the same thing (calling modprobe), + so why not skip the middle man? + +- removing kerneld related stuff from ipc/msg.c made it 40% smaller + +- kmod reports errors through the normal kernel mechanisms, which avoids + the chicken and egg problem of kerneld and modular unix domain sockets diff -ur --new-file old/linux/Documentation/m68k/framebuffer.txt new/linux/Documentation/m68k/framebuffer.txt --- old/linux/Documentation/m68k/framebuffer.txt Wed May 14 07:41:00 1997 +++ new/linux/Documentation/m68k/framebuffer.txt Fri Feb 13 01:30:11 1998 @@ -3,7 +3,7 @@ ---------------------------------- Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) -Last revised: March 23, 1997 +Last revised: January 24, 1998 0. Introduction @@ -23,85 +23,47 @@ -------------------------- From the user's point of view, the frame buffer device looks just like any -other device in /dev. It's a character device using major 29, the minor is -divided into a frame buffer number in the upper 3 bits (allowing max. 8 frame -buffers simultaneously) and a resolution code in the lower 5 bits of the minor. +other device in /dev. It's a character device using major 29; the minor +specifies the frame buffer number. By convention, the following device nodes are used (numbers indicate the device minor numbers): - First frame buffer - 0 = /dev/fb0current Current resolution - 1 = /dev/fb0autodetect Default resolution - 2 = /dev/fb0predefined0 Predefined resolutions (22) - ... - 23 = /dev/fb0predefined21 - 24 = /dev/fb0user0 User defined resolutions (8) - ... - 31 = /dev/fb0user7 - - Second frame buffer - 32 = /dev/fb1current Current resolution - 33 = /dev/fb1autodetect Default resolution - 34 = /dev/fb1predefined0 Predefined resolutions (22) - ... - 55 = /dev/fb1predefined21 - 56 = /dev/fb1user0 User defined resolutions (8) - ... - 63 = /dev/fb1user7 + 0 = /dev/fb0 First frame buffer + 32 = /dev/fb1 Second frame buffer + ... + 224 = /dev/fb7 8th frame buffer -and so on... +For backwards compatibility, you may want to create the following symbolic +links: + + /dev/fb0current -> fb0 + /dev/fb1current -> fb1 -The device with (minor & 31) == 0 (/dev/fb?current) stands for the frame buffer -together with the currently set video parameters; (minor & 31) == 1 -(/dev/fb?autodetect) is the video mode detected at boot time. Any other minor -stands for some predefined or user defined video mode. - -The predefined entries (/dev/fb?predefined*) usually have a device dependent -name, e.g. for major 29, minor 5, we have /dev/fb0multiscan on Amiga and -/dev/fb0ttmid on Atari. These are meant to contain hardware dependent -resolutions. - -The user defined resolutions (/dev/fb?user?) are meant to be filled in by the -user. This way the user can store his favorite 8 resolutions during boot up. - -Note: if you need more than 8 user defined resolutions, you can always override -the predefined resolutions by storing them in one of the predefined entries. -But this is not recommended. Similarly, if there are more than 22 predefined -resolutions, the device writer can decide to store them in the user defined -entries. - -If the device is opened (for writing), the frame buffer driver switches to the -selected video mode. Thus, you can switch video modes by writing to a frame -buffer device, e.g. - - > /dev/fb0ttlow - -will switch your video to TT low mode. Note: if you specify a resolution which -contains a value that's not possible on your hardware, the frame buffer device -will round it up (if possible) or return an error condition. +and so on... The frame buffer devices are also `normal' memory devices, this means, you can read and write their contents. You can, for example, make a screen snapshot by - cp /dev/fb0current myfile + cp /dev/fb0 myfile There also can be more than one frame buffer at a time, e.g. if you have a graphics card in addition to the built-in hardware. The corresponding frame -buffer devices (/dev/fb0* and /dev/fb1* etc.) work independently. +buffer devices (/dev/fb0 and /dev/fb1 etc.) work independently. Application software that uses the frame buffer device (e.g. the X server) will -use /dev/fb0current by default. You can specify an alternative resolution by -setting the environment variable $FRAMEBUFFER to the path name of a frame -buffer device, e.g. (for sh/bash users): +use /dev/fb0 by default (older software uses /dev/fb0current). You can specify +an alternative frame buffer device by setting the environment variable +$FRAMEBUFFER to the path name of a frame buffer device, e.g. (for sh/bash +users): - export FRAMEBUFFER=/dev/fb0multiscan + export FRAMEBUFFER=/dev/fb1 or (for csh users): - setenv FRAMEBUFFER /dev/fb0multiscan + setenv FRAMEBUFFER /dev/fb1 -After this the X server will use the multiscan video mode. +After this the X server will use the second frame buffer. 2. Programmer's View of /dev/fb* @@ -152,23 +114,20 @@ -------------------------------------- Frame buffer resolutions are maintained using the utility `fbset'. It allows to -change the video mode properties of the current or a user defined resolution. -It's main usage is to tune video modes and to store custom resolutions into one -of the /dev/fb?user? entries, e.g. during boot up in one of your /etc/rc.* or -/etc/init.d/* files, after which those resolutions can be used by applications. +change the video mode properties of the current resolution. It's main usage is +to change the current video mode, e.g. during boot up in one of your /etc/rc.* +or /etc/init.d/* files. Fbset uses a video mode database stored in a configuration file, so you can -easily add your own modes and refer to them with a simple identifier. The fbset -install script also creates the special device nodes for the device dependent -predefined resolutions. +easily add your own modes and refer to them with a simple identifier. 4. The X Server --------------- The X server (XF68_FBDev) is the most notable application program for the frame -buffer device. The current X server is part of the XFree86/XFree68 release 3.2 -package and has 2 modes: +buffer device. The current X server is part of the XFree86/XFree68 release +3.3.1 package and has 2 modes: - If the `Display' subsection for the `fbdev' driver in the /etc/XF86Config file contains a @@ -347,7 +306,7 @@ - The mighty kernel sources: o linux/include/linux/fb.h o linux/drivers/char/fbmem.c - o linux/arch/m68k/*/*fb.c + o linux/drivers/video/*fb.c 8. Downloading 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 Sat Nov 29 19:33:18 1997 +++ new/linux/Documentation/m68k/kernel-options.txt Wed Feb 25 07:08:01 1998 @@ -3,8 +3,8 @@ Command Line Options for Linux/m68k =================================== -Date: Oct 6, 1997 -Linux/m68k version: 2.0.21 +Last Update: Nov 28, 1997 +Linux/m68k version: 2.1.64 Author: Roman.Hodek@informatik.uni-erlangen.de (Roman Hodek) Update: jds@kom.auc.dk (Jes Sorensen) @@ -191,6 +191,7 @@ - "ser2": SCC channel B serial port ("Modem2"); parameters: 9600bps, 8N1 - "ser" : default serial port This is "ser2" for a Falcon, and "ser1" for any other machine + - "midi": The MIDI port; parameters: 31250bps, 8N1 - "par" : parallel port The printing routine for this implements a timeout for the case there's no printer connected (else the kernel would @@ -408,19 +409,7 @@ Often, extended interval video hardware has to be activated somehow. For this, see the "sw_*" options below. -4.1.6) sw_acia, sw_snd6, sw_snd7 --------------------------------- - -This specifies the method for turning on extended internal video -hardware, like OverScan. Several methods are in use: - - sw_acia: Set RTS of the keyboard ACIA high - sw_snd6: Set bit 6 of the PSG port A - sw_snd7: Set bit 7 of the PSG port A - -These sub-options are generally only useful together with "internal:". - -4.1.7) external: +4.1.6) external: ---------------- Syntax: @@ -509,13 +498,13 @@ therefore we don't support hardware-dependend functions like hardware-scroll, panning or blanking. -4.1.8) eclock: +4.1.7) eclock: -------------- The external pixel clock attached to the Falcon VIDEL shifter. This currently works only with the ScreenWonder! -4.1.9) monitorcap: +4.1.8) monitorcap: ------------------- Syntax: monitorcap:;;; @@ -532,7 +521,7 @@ The defaults for TV/SC1224/SC1435 cover both PAL and NTSC standards. -4.1.10) keep +4.1.9) keep ------------ If this option is given, the framebuffer device doesn't do any video @@ -578,7 +567,7 @@ type. The second parameter tells the kernel whether to use - track buffering (1) or not (0). The default is machine dependant: + track buffering (1) or not (0). The default is machine-dependent: no for the Medusa and yes for all others. With the two following parameters, you can change the default @@ -650,7 +639,62 @@ can be performed in optimal order. Not all SCSI devices support tagged queuing (:-(). +4.6 switches= +------------- + +Syntax: switches= + + With this option you can switch some hardware lines that are often +used to enable/disable certain hardware extensions. Examples are +OverScan, overclocking, ... + + The is a comma-separated list of the following +items: + + ikbd: set RTS of the keyboard ACIA high + midi: set RTS of the MIDI ACIA high + snd6: set bit 6 of the PSG port A + snd7: set bit 6 of the PSG port A + +It doesn't make sense to mention a switch more than once (no +difference to only once), but you can give as many switches as you +want to enable different features. The switch lines are set as early +as possible during kernel initialization (even before determining the +present hardware.) + + All of the items can also be prefixed with "ov_", i.e. "ov_ikbd", +"ov_midi", ... These options are meant for switching on an OverScan +video extension. The difference to the bare option is that the +switch-on is done after video initialization, and somehow synchronized +to the HBLANK. A speciality is that ov_ikbd and ov_midi are switched +off before rebooting, so that OverScan is disabled and TOS boots +correctly. + + If you give an option both, with and without the "ov_" prefix, the +earlier initialization ("ov_"-less) takes precedence. But the +switching-off on reset still happens in this case. + +4.5) stram_swap= +---------------- + +Syntax: stram_swap=[,] + This option is available only if the kernel has been compiled with +CONFIG_STRAM_SWAP enabled. Normally, the kernel then determines +dynamically whether to actually use ST-RAM as swap space. (Currently, +the fraction of ST-RAM must be less or equal 1/3 of total memory to +enable this swapping.) You can override the kernel's decision by +specifying this option. 1 for means always enable the swap, +even if you have less alternate RAM. 0 stands for never swap to +ST-RAM, even if it's small enough compared to the rest of memory. + + If ST-RAM swapping is enabled, the kernel usually uses all free +ST-RAM as swap "device". (If the kernel resides in ST-RAM, the region +allocated by it is obviously never used for swapping :-) You can also +limit this amount by specifying the second parameter, , if +you want to use parts of ST-RAM as normal system memory. is +in kBytes and the number should be a multiple of 4 (otherwise: rounded +down). 5) Options for Amiga Only: ========================== diff -ur --new-file old/linux/Documentation/md.txt new/linux/Documentation/md.txt --- old/linux/Documentation/md.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/md.txt Mon Feb 2 22:07:47 1998 @@ -0,0 +1,37 @@ +Tools that manage md devices can be found at sweet-smoke.ufr-info-p7.ibp.fr +in public/Linux/md035.tar.gz. + + Marc ZYNGIER + +-- + +You can boot (if you selected boot support in the configuration) with your md +device with the following kernel command line: + +md=,,,,dev0,dev1,...,devn + +md device no. = the number of the md device ... + 0 means md0, + 1 md1, + 2 md2, + 3 md3, + 4 md4 + +raid level = -1 linear mode + 0 striped mode + other modes are currently unsupported. + +chunk size factor = (raid-0 and raid-1 only) + Set the chunk size as PAGE_SIZE << n. + +fault level = (raid-1 only) + Set the maximum fault number as n. + Currently unsupported due to lack of boot support for raid1. + +dev0-devn: e.g. /dev/hda1,/dev/hdc1,/dev/sda1,/dev/sdb1 + +my loadlin line looks like this: + +e:\loadlin\loadlin e:\zimage root=/dev/md0 md=0,0,4,0,/dev/hdb2,/dev/hdc3 ro + + Harald Hoyer diff -ur --new-file old/linux/Documentation/modules.txt new/linux/Documentation/modules.txt --- old/linux/Documentation/modules.txt Sun Dec 28 21:05:44 1997 +++ new/linux/Documentation/modules.txt Tue Mar 10 23:43:13 1998 @@ -10,6 +10,12 @@ features that the kernel now supports. The current required version is listed in the file linux/Documentation/Changes. +* * * NOTE * * * +The kernel has been changed to remove kerneld support and use +the new kmod support. Keep this in mind when reading this file. Kmod +does the exact same thing as kerneld, but doesn't require an external +program (see Documentation/kmod.txt) + In the beginning... ------------------- diff -ur --new-file old/linux/Documentation/nbd.txt new/linux/Documentation/nbd.txt --- old/linux/Documentation/nbd.txt Sat Nov 29 19:33:18 1997 +++ new/linux/Documentation/nbd.txt Thu Feb 26 20:01:24 1998 @@ -4,19 +4,19 @@ means, that it works on my computer, and it worked on one of school computers. - What is it: With this think compiled in kernel, linux can use remote - server as one of its block devices. So every time client computer - wants to read /dev/nd0, it will send request over TCP to server, which - will reply with data readed. This can be used for stations with - low-disk space (or even disklesses - if you boot from floppy) to - borrow disk space from other computer. Unlike NFS, it is possible to - put any filesystem on it etc. It is impossible to use NBD as root - filesystem, since it requires user-level program to start. It also + What is it: With this compiled in the kernel, linux can use a remote + server as one of its block devices. So every time the client computer + wants to read /dev/nd0, it sends a request over TCP to the server, which + will reply with the data read. This can be used for stations with + low-disk space (or even diskless - if you boot from floppy) to + borrow disk space from another computer. Unlike NFS, it is possible to + put any filesystem on it etc. It is impossible to use NBD as a root + filesystem, since it requires a user-level program to start. It also allows you to run block-device in user land (making server and client - physicaly same computer, communicating using loopback). + physically the same computer, communicating using loopback). Current state: It currently works. Network block device looks like - being pretty stable. I originaly thought that it is impossible to swap + being pretty stable. I originally thought that it is impossible to swap over TCP. It turned out not to be true - swapping over TCP now works and seems to be deadlock-free, but it requires heavy patches into Linux's network layer. @@ -30,8 +30,8 @@ ... Protocol: Userland program passes file handle with connected TCP - socket to actuall kernel driver. This way, kernel does not have to - care about connecting etc. Protocol is rather simple: If driver is + socket to actual kernel driver. This way, the kernel does not have to + care about connecting etc. Protocol is rather simple: If the driver is asked to read from block device, it sends packet of following form "request" (all data are in network byte order): @@ -48,7 +48,7 @@ structure "reply": __u32 magic; must be equal to - __u64 handle; handle copyied from request + __u64 handle; handle copied from request __u32 error; 0 = operation completed successfully, else error code ... in case of read operation with no error, diff -ur --new-file old/linux/Documentation/networking/alias.txt new/linux/Documentation/networking/alias.txt --- old/linux/Documentation/networking/alias.txt Wed Jan 3 19:36:23 1996 +++ new/linux/Documentation/networking/alias.txt Sun Mar 1 23:40:39 1998 @@ -1,32 +1,10 @@ -NET_ALIAS device aliasing v0.4x -=============================== - The main step taken in versions 0.40+ is the implementation of a - device aliasing mechanism that creates *actual* devices. - This development includes NET_ALIAS (generic aliasing) plus IP_ALIAS - (specific IP) support. - -Features --------- -o ACTUAL alias devices created & inserted in dev chain -o AF_ independent: net_alias_type objects. Generic aliasing engine. -o AF_INET optimized -o hashed alias address lookup -o net_alias_type objs registration/unreg., module-ables. -o /proc/net/aliases & /proc/net/alias_types entries - -o IP alias implementation: static or runtime module. - -Usage (IP aliasing) -------------------- - A very first step to test if you are running a net_alias-ed kernel - is to check /proc/net/aliases & /proc/net/alias_types entries: - # cat /proc/net/alias* - - For IP aliasing you must have IP_ALIAS support included by - static linking ('y' to 2nd question above), or runtime module - insertion ('m' to 2nd q. above): - # insmod /usr/src/linux/modules/ip_alias.o (1.3.xx) - # insmod /usr/src/ip_alias/ip_alias.o (1.2.xx) see above. + +IP-Aliasing: +============ + + +o For IP aliasing you must have IP_ALIAS support included by static + linking. o Alias creation. Alias creation is done by 'magic' iface naming: eg. to create a @@ -42,50 +20,30 @@ for eth0:0) o Alias deletion. - Also done by magic naming, eg: + Also done by shutting the interface down: + + # ifconfig eth0:0 down + ~~~~~~~~~~ -> will delete alias - # ifconfig eth0:0- 0 (maybe any address) - ~~~ -> will delete alias (note '-' after dev name) - alias device is closed before deletion, so all network stuff that - points to it (routes, arp entries, ...) will be released. Alias (re-)configuring - Aliases *are* devices, so you configure and refer to them as usual (ifconfig, - route, etc). - -o Procfs entries - 2 entries are added to help fetching alias runtime configuration: - a) /proc/net/alias_types - Will show you alias_types registered (ie. address families that - can be aliased). - eg. for IP aliasing with 1 alias configured: - - # cat /proc/net/alias_types - type name n_attach - 2 ip 1 - - b) /proc/net/aliases - Will show aliased devices info, eg (same as above): - - # cat /proc/net/aliases - device family address - eth0:0 2 200.1.1.1 + + Aliases are no real devices, but should be able to configure and + refer to them as usual (ifconfig, route, etc). Relationship with main device ----------------------------- - - On main device closing, all aliases will be closed and freed. - - Each new alias created is inserted in dev_chain just before next - main device (aliases get 'stacked' after main_dev), eg: - lo->eth0->eth0:0->eth0:2->eth1->0 - If eth0 is unregistered, all it aliases will also be: - lo->eth1->0 + + - the main device is an alias itself like additional aliases and can + be shut down without deleting other aliases. Contact ------- Please finger or e-mail me: Juan Jose Ciarlante - - + +Updated by Erik Schoenfelder + ; local variables: ; mode: indented-text ; mode: auto-fill diff -ur --new-file old/linux/Documentation/networking/scc.txt new/linux/Documentation/networking/scc.txt --- old/linux/Documentation/networking/scc.txt Sat Nov 29 19:33:18 1997 +++ new/linux/Documentation/networking/scc.txt Thu Jan 1 01:00:00 1970 @@ -1,23 +0,0 @@ - -You will find subset of the documentation in - - linux/Documentation/networking/z8530drv.txt - -To use this driver you MUST have the full package from: - -Internet: -========= - -1. db0bm.automation.fh-aachen.de/incoming/dl1bke/z8530drv-utils-3.0.tar.gz - -2. ftp.ucsd.edu:/hamradio/packet/tcpip/incoming/z8530drv-utils-3.0.tar.gz - If you can't find it there, try .../tcpip/linux/z8530drv-utils-3.0.tar.gz - -and various mirrors (i.e. nic.switch.ch) - -The package includes the utilities necessary to initialize and -control the driver. - -Joerg Reuter ampr-net: dl1bke@db0pra.ampr.org - AX-25 : DL1BKE @ DB0ACH.#NRW.DEU.EU - Internet: jreuter@lykos.oche.de diff -ur --new-file old/linux/Documentation/networking/z8530drv.txt new/linux/Documentation/networking/z8530drv.txt --- old/linux/Documentation/networking/z8530drv.txt Sun Nov 30 01:29:37 1997 +++ new/linux/Documentation/networking/z8530drv.txt Tue Feb 3 00:18:15 1998 @@ -4,9 +4,9 @@ Internet: ========= -1. ftp://db0bm.automation.fh-aachen.de/incoming/z8530drv/z8530drv-utils-3.0.tar.gz +1. ftp://ftp.ccac.rwth-aachen.de/pub/jr/z8530drv-utils-3.0-1.tar.gz -2. ftp://ftp.pspt.fi/pub/ham/linux/ax25/z8530drv-utils-3.0.tar.gz +2. ftp://ftp.pspt.fi/pub/ham/linux/ax25/z8530drv-utils-3.0-1.tar.gz 3. ftp://ftp.ucsd.edu/hamradio/packet/tcpip/incoming/z8530drv-utils-3.0.tar.gz If you can't find it there, try .../tcpip/linux/z8530drv-utils-3.0.tar.gz @@ -23,7 +23,7 @@ ******************************************************************** - (c) 1993,1997 by Joerg Reuter DL1BKE + (c) 1993,1998 by Joerg Reuter DL1BKE portions (c) 1993 Guido ten Dolle PE1NNZ diff -ur --new-file old/linux/Documentation/paride.txt new/linux/Documentation/paride.txt --- old/linux/Documentation/paride.txt Sun Dec 28 21:05:44 1997 +++ new/linux/Documentation/paride.txt Sun Jan 25 18:59:59 1998 @@ -55,7 +55,7 @@ pd IDE disk pcd ATAPI CD-ROM pf ATAPI disk - pt ATAPI tape (not yet available) + pt ATAPI tape (Support for ATAPI CD-R and CD-RW drives is not yet in development, but this may change.) diff -ur --new-file old/linux/Documentation/riscom8.txt new/linux/Documentation/riscom8.txt --- old/linux/Documentation/riscom8.txt Fri Apr 26 11:12:36 1996 +++ new/linux/Documentation/riscom8.txt Thu Mar 5 20:55:06 1998 @@ -1,5 +1,5 @@ This is the README for RISCom/8 multi-port serial driver - (C) 1994-1996 D.Gorodchanin (begemot@bgm.rosrpint.net) + (C) 1994-1996 D.Gorodchanin (pgmdsg@ibi.com) See file LICENSE for terms and conditions. NOTE: English is not my native language. diff -ur --new-file old/linux/Documentation/smart-config.txt new/linux/Documentation/smart-config.txt --- old/linux/Documentation/smart-config.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/smart-config.txt Thu Jan 22 02:51:11 1998 @@ -0,0 +1,103 @@ +Smart CONFIG_* Dependencies +Fri 2 Dec 1997 + +Michael Chastain +Werner Almesberger +Martin von Loewis + +Here is the problem: + + Suppose that drivers/net/foo.c has the following lines: + + #include + + ... + + #ifdef CONFIG_FOO_AUTOFROB + /* Code for auto-frobbing */ + #else + /* Manual frobbing only */ + #endif + + ... + + #ifdef CONFIG_FOO_MODEL_TWO + /* Code for model two */ + #endif + + Now suppose the user (the person building kernels) reconfigures the + kernel to change some unrelated setting. This will regenerate the + file include/linux/autoconf.h, which will cause include/linux/config.h + to be out of date, which will cause drivers/net/foo.c to be recompiled. + + Most kernel sources, perhaps 80% of them, have at least one CONFIG_* + dependency somewhere. So changing _any_ CONFIG_* setting requires + almost _all_ of the kernel to be recompiled. + +Here is the solution: + + We've made the dependency generator, mkdep.c, smarter. Instead of + generating this dependency: + + drivers/net/foo.c: include/linux/config.h + + It now generates these dependencies: + + drivers/net/foo.c: \ + include/config/foo_autofrob.h \ + include/config/foo_model_two.h + + So drivers/net/foo.c depends only on the CONFIG_* lines that + it actually uses. + + A new program, split-include.c, runs at the end of make config (also + make oldconfig, make menuconfig, and make xconfig). split-include + reads include/linux/autoconf.h and updates the include/linux/*.h + directory, writing one file per option. It updates only the files + that changed. + + mkdep.c also generates much better warning messages for missing + or unneeded lines. In fact, you can get these + messages without generating dependencies with the new top-level + target 'make checkconfig'. + +Flag Dependencies + + Martin Von Loewis contributed another feature to this patch: + 'flag dependencies'. The idea is that a .o file depends on + the compilation flags used to build it. The file foo.o has + its flags stored in .flags.foo.o. + + Suppose the user changes the foo driver from resident to + modular, 'make' will notice that the foo.o was not compiled + with -DMODULE and will recompile foo.c. + + Flag dependencies also work with per-source-file flags such + as those in drivers/net/CONFIG. + + All .a and .o files made from C source or with 'ld' or 'ar' + have flag dependencies. .S files do not have flag dependencies. + +Per-source-file Flags + + You can specify compilation flags for individual source files + like this: + + CFLAGS_foo.o = -DSPECIAL_FOO_DEFINE + + This helps clean up drivers/net/Makefile, drivers/scsi/Makefile, + and several other Makefiles. + +Credit + + Werner Almesberger had the original idea and wrote the first + version of this patch. + + Michael Chastain picked it up and continued development. He is + now the principal author and maintainer. Report bugs to him, + or to all three people together. + + Martin von Loewis wrote flag dependencies, with some modifications + by Michael Chastain. + + Thanks to all of the beta testers. diff -ur --new-file old/linux/Documentation/stallion.txt new/linux/Documentation/stallion.txt --- old/linux/Documentation/stallion.txt Fri Dec 19 21:30:53 1997 +++ new/linux/Documentation/stallion.txt Wed Feb 4 23:52:16 1998 @@ -2,10 +2,10 @@ Stallion Multiport Serial Driver Readme --------------------------------------- -Copyright (C) 1994-1997, Stallion Technologies (support@stallion.com). +Copyright (C) 1994-1998, Stallion Technologies (support@stallion.com). -Version: 5.4.1 -Date: 19DEC97 +Version: 5.4.3 +Date: 04FEB98 @@ -20,7 +20,7 @@ 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's that contain these archives). The file +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 @@ -31,12 +31,12 @@ have the latest version are tsx-11.mit.edu, sunsite.unc.edu and their mirrors. -ftp.stallion.com:/drivers/ata5/Linux/stallion-5.4.0.tar.gz -tsx-11.mit.edu:/pub/linux/BETA/serial/stallion/stallion-5.4.0.tar.gz -sunsite.unc.edu:/pub/Linux/kernel/patches/serial/stallion-5.4.0.tar.gz +ftp.stallion.com:/drivers/ata5/Linux/stallion-5.4.2.tar.gz +tsx-11.mit.edu:/pub/linux/packages/stallion/stallion-5.4.2.tar.gz +sunsite.unc.edu:/pub/Linux/kernel/patches/serial/stallion-5.4.2.tar.gz As of the printing of this document the latest version of the driver -utility package is 5.4.0. If a later version is now available then you +utility package is 5.4.2. 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 diff -ur --new-file old/linux/Documentation/sysctl/README new/linux/Documentation/sysctl/README --- old/linux/Documentation/sysctl/README Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sysctl/README Thu Feb 26 20:10:37 1998 @@ -0,0 +1,74 @@ + +Documentation for /proc/sys/*/* version 0.1 + (c) 1998, 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 +the source...' + +Well, this documentation is written because some people either +don't know they need to tweak something, or because they don't +have the time or knowledge to read the source code. + +Furthermore, the programmers who built sysctl have built it to +be actually used, not just for the fun of programming it :-) + +============================================================== + +Legal blurb: + +As usual, there are two main things to consider: +1. you get what you pay for +2. it's free + +The consequences are that I won't guarantee the correctness of +this document, and if you come to me complaining about how you +screwed up your system because of wrong documentation, I won't +feel sorry for you. I might even laugh at you... + +But of course, if you _do_ manage to screw up your system using +only the sysctl options used in this file, I'd like to hear of +it. Not only to have a great laugh, but also to make sure that +you're the last RTFMing person to screw up. + +In short, e-mail your suggestions, corrections and / or horror +stories to: + +Rik van Riel. + +============================================================== + +Introduction: + +Sysctl is a means of configuring certain aspects of the kernel +at run-time, and the /proc/sys/ directory is there so that you +don't even need special tools to do it! +In fact, there are only four things needed to use these config +facilities: +- a running Linux system +- root access +- common sense (this is especially hard to come by these days) +- knowledge of what all those values mean + +As a quick 'ls /proc/sys' will show, the directory consists of +several (arch-dependent?) subdirs. Each subdir is mainly about +one part of the kernel, so you can do configuration on a piece +by piece basis, or just some 'thematic frobbing'. + +The subdirs are about: +debug/ +dev/ device specific information (eg dev/cdrom/info) +fs/ specific filesystems + binfmt_misc +kernel/ global kernel info / tuning + open file / inode tuning + miscellaneous stuff +net/ networking stuff, for documentation look in: + +proc/ +vm/ memory management tuning + buffer and cache management + +These are the subdirs I have on my system. There might be more +or other subdirs in another setup. If you see another dir, I'd +really like to hear about it :-) diff -ur --new-file old/linux/Documentation/sysctl/kernel.txt new/linux/Documentation/sysctl/kernel.txt --- old/linux/Documentation/sysctl/kernel.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sysctl/kernel.txt Thu Feb 26 20:09:16 1998 @@ -0,0 +1,208 @@ + +Documentation for /proc/sys/kernel/* version 0.1 + (c) 1998, 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. + +The files in this directory can be used to tune and monitor +miscellaneous and general things in the operation of the Linux +kernel. Since some of the files _can_ be used to screw up your +system, it is advisable to read both documentation and source +before actually making adjustments. + +Currently, these files are in /proc/sys/kernel: +- ctrl-alt-del +- dentry-state +- domainname +- file-max +- file-nr +- hostname +- inode-max +- inode-nr +- inode-state +- osrelease +- ostype +- panic +- printk +- securelevel +- version + +============================================================== + +ctrl-alt-del: + +When the value in this file is 0, ctrl-alt-del is trapped and +sent to the init(1) program to handle a graceful restart. +When, however, the value is > 0, Linux's reaction to a Vulcan +Nerve Pinch (tm) will be an immediate reboot, without even +syncing it's dirty buffers. + +Note: when a program (like dosemu) has the keyboard in 'raw' +mode, the ctrl-alt-del is intercepted by the program before it +ever reaches the kernel tty layer, and it's up to the program +to decide what to do with it. + +============================================================== + +dentry-state: + +From linux/fs/dentry.c: +-------------------------------------------------------------- +struct { + int nr_dentry; + int nr_unused; + int age_limit; /* age in seconds */ + int want_pages; /* pages requested by system */ + int dummy[2]; +} dentry_stat = {0, 0, 45, 0,}; +-------------------------------------------------------------- + +Dentries are dynamically allocated and deallocated, and +nr_dentry seems to be 0 all the time. Hence it's safe to +assume that only nr_unused, age_limit and want_pages are +used. Nr_unused seems to be exactly what it's name says. +Age_limit is the age in seconds after which dcache entries +can be reclaimed when memory is short and want_pages is +nonzero when shrink_dcache_pages() has been called and the +dcache isn't pruned yet. + +============================================================== + +domainname & hostname: + +These files can be controlled to set the domainname and +hostname of your box. For the classic darkstar.frop.org +a simple: +# echo "darkstar" > /proc/sys/kernel/hostname +# echo "frop.org" > /proc/sys/kernel/domainname +would suffice to set your hostname and domainname. + +============================================================== + +file-max & file-nr: + +The kernel allocates filehandles dynamically, but as yet it +doesn't free them again... + +The value in file-max denotes the maximum number of file- +handles that the Linux kernel will allocate. When you get lots +of error messages about running out of file handles, you might +want to increase this limit. + +The three values in file-nr denote the number of allocated +file handles, the number of used file handles and the maximum +number of file handles. When the allocated filehandles come +close to the maximum, but the number of actually used ones is +far behind, you've encountered a peek in your filehandle usage +and you don't need to increase the maximum. + +============================================================== + +inode-max, inode-nr & inode-state: + +As with filehandles, the kernel allocates the inode structures +dynamically, but can't free them yet... + +The value in inode-max denotes the maximum number of inode +handlers. This value should be 3-4 times larger as the value +in file-max, since stdin, stdout and network sockets also +need an inode struct to handle them. When you regularly run +out of inodes, you need to increase this value. + +The file inode-nr contains the first two items from +inode-state, so we'll skip to that file... + +Inode-state contains three actual numbers and four dummies. +The actual numbers are, in order of appearance, nr_inodes, +nr_free_inodes and preshrink. + +Nr_inodes stands for the number of inodes the system has +allocated, this can be slightly more than inode-max because +Linux allocates them one pagefull at a time. + +Nr_free_inodes represents the number of free inodes (?) and +preshrink is nonzero when the nr_inodes > inode-max and the +system needs to prune the inode list instead of allocating +more. + +============================================================== + +osrelease, ostype & version: + +# cat osrelease +2.1.88 +# cat ostype +Linux +# cat version +#5 Wed Feb 25 21:49:24 MET 1998 + +The files osrelease and ostype should be clear enough. Version +needs a little more clarification however. The '#5' means that +this is the fifth kernel built from this source base and the +date behind it indicates the time the kernel was built. +The only way to tune these values is to rebuild the kernel :-) + +============================================================== + +panic: + +The value in this file represents the number of seconds the +kernel waits before rebooting on a panic. When you use the +software watchdog, the recommended setting is 60. + +============================================================== + +printk: + +The four values in printk denote: console_loglevel, +default_message_loglevel, minimum_console_level and +default_console_loglevel respectively. + +These values influence printk() behavior when printing or +logging error messages. See 'man 2 syslog' for more info on +the different loglevels. + +- console_loglevel: messages with a higher priority than + this will be printed to the console +- default_message_level: messages without an explicit priority + will be printed with this priority +- minimum_console_loglevel: minimum (highest) value to which + console_loglevel can be set +- default_console_loglevel: default value for console_loglevel + +Note: a quick look in linux/kernel/printk.c will reveal that +these variables aren't put inside a structure, so their order +in-core isn't formally guaranteed and garbage values _might_ +occur when the compiler changes. (???) + +============================================================== + +securelevel: + +When the value in this file is nonzero, root is prohibited +from: +- changing the immutable and append-only flags on files +- changing sysctl things (limited ???) + +============================================================== + +real-root-dev: (CONFIG_INITRD only) + +This file is used to configure the real root device when using +an initial ramdisk to configure the system before switching to +the 'real' root device. See linux/Documentation/initrd.txt for +more info. + +============================================================== + +reboot-cmd: (Sparc only) + +??? 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. ??? + diff -ur --new-file old/linux/Documentation/sysctl/vm.txt new/linux/Documentation/sysctl/vm.txt --- old/linux/Documentation/sysctl/vm.txt Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/sysctl/vm.txt Thu Mar 12 19:56:01 1998 @@ -0,0 +1,245 @@ + +Documentation for /proc/sys/vm/* version 0.1 + (c) 1998, 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. + +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. + +Currently, these files are in /proc/sys/vm: +- bdflush +- buffermem +- freepages +- overcommit_memory +- swapctl +- swapout_interval + +============================================================== + +bdflush: + +This file controls the operation of the bdflush kernel +daemon. The source code to this struct can be found in +linux/mm/buffer.c. It currently contains 9 integer values, +of which 6 are actually used by the kernel. + +From linux/fs/buffer.c: +-------------------------------------------------------------- +union bdflush_param{ + struct { + int nfract; /* Percentage of buffer cache dirty to + activate bdflush */ + int ndirty; /* Maximum number of dirty blocks to + write out per wake-cycle */ + int nrefill; /* Number of clean buffers to try to + obtain each time we call refill */ + int nref_dirt; /* Dirty buffer threshold for activating + bdflush when trying to refill buffers. */ + int dummy1; /* unused */ + int age_buffer; /* Time for normal buffer to age before + we flush it */ + int age_super; /* Time for superblock to age before we + flush it */ + int dummy2; /* unused */ + int dummy3; /* unused */ + } b_un; + unsigned int data[N_PARAM]; +} bdf_prm = {{40, 500, 64, 256, 15, 30*HZ, 5*HZ, 1884, 2}}; +-------------------------------------------------------------- + +The first parameter governs the maximum number of of dirty +buffers in the buffer cache. Dirty means that the contents +of the buffer still have to be written to disk (as opposed +to a clean buffer, which can just be forgotten about). +Setting this to a high value means that Linux can delay disk +writes for a long time, but it also means that it will have +to do a lot I/O at once when memory becomes short. A low +value will spread out disk I/O more evenly. + +The second parameter (ndirty) gives the maximum number of +dirty buffers that bdflush can write to the disk in one time. +A high value will mean delayed, bursty I/O, while a small +value can lead to memory shortage when bdflush isn't woken +up often enough... + +The third parameter (nrefill) is the number of buffers that +bdflush will add to the list of free buffers when +refill_freelist() is called. It is necessary to allocate free +buffers beforehand, since the buffers often are of a different +size than memory pages and some bookkeeping needs to be done +beforehand. The higher the number, the more memory will be +wasted and the less often refill_freelist() will need to run. + +When refill_freelist() comes across more than nref_dirt dirty +buffers, it will wake up bdflush. + +Finally, the age_buffer and age_super parameters govern the +maximum time Linux waits before writing out a dirty buffer +to disk. The value is expressed in jiffies (clockticks), the +number of jiffies per second is 100, except on Alpha machines +(1024). Age_buffer is the maximum age for data blocks, while +age_super is for filesystem metadata. + +============================================================== +buffermem: + +The three values in this file correspond to the values in +the struct buffer_mem. It controls how much memory should +be used for buffer and cache memory. Note that memorymapped +files are also counted as cache memory... + +The values are: +min_percent -- this is the minumum percentage of memory + that should be spent on buffer + page cache +borrow_percent -- when Linux is short on memory, and buffer + and cache use more than this percentage of + memory, free pages are stolen from them +max_percent -- this is the maximum amount of memory that + can be used for buffer and cache memory + +============================================================== +freepages: + +This file contains the values in the struct freepages. That +struct contains three members: min, low and high. + +These numbers are used by the VM subsystem to keep a reasonable +number of pages on the free page list, so that programs can +allocate new pages without having to wait for the system to +free used pages first. The actual freeing of pages is done +by kswapd, a kernel daemon. + +min -- when the number of free pages reaches this + level, only the kernel can allocate memory + for _critical_ tasks only +low -- when the number of free pages drops below + this level, kswapd is woken up immediately +high -- this is kswapd's target, when more than + pages are free, kswapd will stop swapping. + +When the number of free pages is between low and high, +and kswapd hasn't run for swapout_interval jiffies, then +kswapd is woken up too. See swapout_interval for more info. + +When free memory is always low on your system, and kswapd has +trouble keeping up with allocations, you might want to +increase these values, especially high and perhaps low. +I've found that a 1:2:4 relation for these values tend to work +rather well in a heavily loaded system. + +============================================================== + +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. + +From linux/mm/mmap.c: +-------------------------------------------------------------- +static inline int vm_enough_memory(long pages) +{ + /* Stupid algorithm to decide if we have enough memory: while + * simple, it hopefully works in most obvious cases.. Easy to + * fool it, 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; +} + +============================================================== + +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' +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, it's age +is adjusted according to the following scheme: +- if the page was used since the last time we scanned, it's + age is increased sc_page_advance (default 3) up to a maximum + of sc_max_page_age (default 20) +- else (it wasn't used) it's age is decreased 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 +agressiveness 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 the how many tries kswapd will do in order +to swapout one page / buffer. These values can be used to +finetune the ratio between user pages and buffer/cache memory. +When you find that your Linux system is swapping out too much +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. + +============================================================== + +swapout_interval: + +The single value in this file controls the amount of time +between successive wakeups of kswapd when nr_free_pages is +between free_pages_low and free_pages_high. The default value +of HZ/4 is usually right, but when kswapd can't keep up with +the number of allocations in your system, you might want to +decrease this number. + diff -ur --new-file old/linux/Documentation/transname.txt new/linux/Documentation/transname.txt --- old/linux/Documentation/transname.txt Tue Jun 17 01:35:53 1997 +++ new/linux/Documentation/transname.txt Thu Feb 26 20:01:24 1998 @@ -20,7 +20,7 @@ filesystems at all clients, not at the server. Linux transname overcomes this problem by allowing filenames -to be context-dependend. For example, if you have a file /etc/config +to be context-dependent. For example, if you have a file /etc/config that should differ on the hosts "myserver" and "myclient", you just create two different files named /etc/config#host=myserver# and /etc/config#host=myclient# . On host "myserver", the file diff -ur --new-file old/linux/MAINTAINERS new/linux/MAINTAINERS --- old/linux/MAINTAINERS Tue Jan 13 00:21:04 1998 +++ new/linux/MAINTAINERS Wed Mar 18 06:21:04 1998 @@ -156,7 +156,9 @@ DAMA SLAVE for AX.25 P: Joerg Reuter -M: jreuter@lykos.oche.de +M: jreuter@poboxes.com +W: http://www.rat.de/jr/ +W: http://qsl.net/dl1bke/ L: linux-hams@vger.rutgers.edu S: Maintained @@ -273,8 +275,8 @@ L: linux-hams@vger.rutgers.edu S: Maintained -HP100: Driver for HP 10/100 Mbit/s Network Adapter Series -P: Jarsolav Kysela +HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series +P: Jaroslav Kysela M: perex@jcu.cz S: Maintained @@ -346,8 +348,8 @@ S: Maintained MENUCONFIG: -P: William Roadcap -M: roadcapw@cfw.com +P: Michael Elizabeth Chastain +M: mec@shout.net L: linux-kernel@vger.rutgers.edu S: Maintained @@ -371,6 +373,8 @@ S: Maintained NCP FILESYSTEM: +P: Petr Vandrovec +M: vandrove@vc.cvut.cz P: Volker Lendecke M: lendecke@Math.Uni-Goettingen.de L: linware@sh.cvut.cz @@ -476,7 +480,7 @@ RISCOM8 DRIVER: P: Dmitry Gorodchanin -M: begemot@bgm.rosprint.net +M: pgmdsg@ibi.com L: linux-kernel@vger.rutgers.edu S: Maintained @@ -516,8 +520,8 @@ S: Maintained SPARC: -P: David S. Miller -M: davem@caip.rutgers.edu +P: Eddie C. Dost +M: ecd@skynet.be L: sparclinux@vger.rutgers.edu S: Maintained @@ -600,9 +604,17 @@ M: jt@hplb.hpl.hp.com S: Maintained +WD7000 SCSI DRIVER +P: Miroslav Zagorac +M: zaga@fly.cc.fer.hr +L: linux-scsi@vger.rutgers.edu +S: Maintained + Z8530 DRIVER FOR AX.25 P: Joerg Reuter -M: jreuter@lykos.oche.de +M: jreuter@poboxes.com +W: http://www.rat.de/jr/ +W: http://qsl.net/dl1bke/ L: linux-hams@vger.rutgers.edu S: Maintained diff -ur --new-file old/linux/Makefile new/linux/Makefile --- old/linux/Makefile Fri Mar 27 02:41:48 1998 +++ new/linux/Makefile Fri Mar 27 02:42:24 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 79 +SUBLEVEL = 90 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) @@ -9,12 +9,9 @@ # because it makes re-config very ugly and too many fundamental files depend # on "CONFIG_SMP" # -# NOTE! SMP is experimental. See the file Documentation/SMP.txt +# For UP operations COMMENT THIS OUT, simply setting SMP = 0 won't work # SMP = 1 -# -# SMP profiling options -# SMP_PROF = 1 .EXPORT_ALL_VARIABLES: @@ -88,7 +85,7 @@ # standard CFLAGS # -CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -g ifdef CONFIG_CPP CFLAGS := $(CFLAGS) -x c++ @@ -97,11 +94,6 @@ ifdef SMP CFLAGS += -D__SMP__ AFLAGS += -D__SMP__ - -ifdef SMP_PROF -CFLAGS += -D__SMP_PROF__ -AFLAGS += -D__SMP_PROF__ -endif endif # @@ -215,21 +207,29 @@ oldconfig: symlinks scripts/split-include $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in - scripts/split-include include/linux/autoconf.h include/config + if [ -r include/linux/autoconf.h ]; then \ + scripts/split-include include/linux/autoconf.h include/config; \ + fi xconfig: symlinks scripts/split-include $(MAKE) -C scripts kconfig.tk wish -f scripts/kconfig.tk - scripts/split-include include/linux/autoconf.h include/config + 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 $(MAKE) -C scripts/lxdialog all $(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in - scripts/split-include include/linux/autoconf.h include/config + if [ -r include/linux/autoconf.h ]; then \ + scripts/split-include include/linux/autoconf.h include/config; \ + fi config: symlinks scripts/split-include $(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in - scripts/split-include include/linux/autoconf.h include/config + if [ -r include/linux/autoconf.h ]; then \ + scripts/split-include include/linux/autoconf.h include/config; \ + fi linuxsubdirs: dummy set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done @@ -266,6 +266,7 @@ include/linux/version.h: ./Makefile @echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > .ver @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver + @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 @@ -348,14 +349,16 @@ clean: archclean rm -f kernel/ksyms.lst include/linux/compile.h - rm -f `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` - rm -f `find . -type f -name 'core' -print` - rm -f `find . -name '.*.flags' -print` + rm -f core `find . -name '*.[oas]' ! -regex '.*lxdialog/.*' -print` + rm -f core `find . -type f -name 'core' -print` + rm -f core `find . -name '.*.flags' -print` rm -f vmlinux System.map rm -f .tmp* rm -f drivers/char/consolemap_deftbl.c drivers/char/conmakehash rm -f drivers/sound/bin2hex drivers/sound/hex2hex - rm -f `find modules/ -type f -print` + if [ -d modules ]; then \ + rm -f core `find modules/ -type f -print`; \ + fi rm -f submenu* mrproper: clean @@ -373,6 +376,7 @@ rm -f include/asm rm -rf include/config rm -f .depend `find . -name .depend -print` + rm -f core `find . -size 0 -print` rm -f .hdepend scripts/mkdep scripts/split-include rm -f $(TOPDIR)/include/linux/modversions.h rm -rf $(TOPDIR)/include/linux/modules @@ -404,7 +408,7 @@ depend dep: dep-files $(MODVERFILE) checkconfig: - perl -w scripts/checkconfig.pl `find $(FINDHPATH) $(SUBDIRS) -name '*.[hcS]' -print | sort` + perl -w scripts/checkconfig.pl `find * -name '*.[hcS]' -print | sort` ifdef CONFIGURATION ..$(CONFIGURATION): diff -ur --new-file old/linux/Rules.make new/linux/Rules.make --- old/linux/Rules.make Mon Jan 5 10:41:01 1998 +++ new/linux/Rules.make Wed Jan 21 23:32:14 1998 @@ -56,7 +56,7 @@ echo 'ifeq ($(strip $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@)),$$(strip $$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags %.o: %.s $(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $< @@ -82,7 +82,7 @@ echo 'ifeq ($(strip $(EXTRA_LDFLAGS) $(ALL_O)),$$(strip $$(EXTRA_LDFLAGS) $$(ALL_O)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags endif # O_TARGET # @@ -96,7 +96,7 @@ echo 'ifeq ($(strip $(EXTRA_ARFLAGS) $(LX_OBJS) $(L_OBJS)),$$(strip $$(EXTRA_ARFLAGS) $$(LX_OBJS) $$(L_OBJS)))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags endif # @@ -218,7 +218,7 @@ echo 'ifeq ($(strip $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -DEXPORT_SYMTAB),$$(strip $$(CFLAGS) $$(EXTRA_CFLAGS) $$(CFLAGS_$@) -DEXPORT_SYMTAB))' ; \ echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \ echo 'endif' \ - ) > .$@.flags + ) > $(dir $@)/.$(notdir $@).flags endif endif # CONFIG_MODULES diff -ur --new-file old/linux/arch/alpha/Makefile new/linux/arch/alpha/Makefile --- old/linux/arch/alpha/Makefile Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/Makefile Thu Feb 12 22:31:28 1998 @@ -18,8 +18,12 @@ SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm arch/alpha/lib \ arch/alpha/math-emu CORE_FILES := arch/alpha/kernel/kernel.o arch/alpha/mm/mm.o $(CORE_FILES) -LIBS := $(TOPDIR)/arch/alpha/math-emu/math-emu.a \ - $(TOPDIR)/arch/alpha/lib/lib.a $(LIBS) $(TOPDIR)/arch/alpha/lib/lib.a + +ifeq ($(CONFIG_MATHEMU),y) + CORE_FILES := $(CORE_FILES) arch/alpha/math-emu/math-emu.o +endif + +LIBS := arch/alpha/lib/lib.a $(LIBS) arch/alpha/lib/lib.a MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot diff -ur --new-file old/linux/arch/alpha/config.in new/linux/arch/alpha/config.in --- old/linux/arch/alpha/config.in Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/config.in Tue Mar 10 23:43:13 1998 @@ -23,7 +23,7 @@ if [ "$CONFIG_MODULES" = "y" ]; then MODULES=y bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD + bool 'Kernel module loader' CONFIG_KMOD fi endmenu @@ -46,6 +46,8 @@ EB64+ CONFIG_ALPHA_EB64P \ EB164 CONFIG_ALPHA_EB164 \ PC164 CONFIG_ALPHA_PC164 \ + LX164 CONFIG_ALPHA_LX164 \ + SX164 CONFIG_ALPHA_SX164 \ Jensen CONFIG_ALPHA_JENSEN \ Noname CONFIG_ALPHA_NONAME \ Mikasa CONFIG_ALPHA_MIKASA \ @@ -54,6 +56,7 @@ Miata CONFIG_ALPHA_MIATA \ Sable CONFIG_ALPHA_SABLE \ AlphaBook1 CONFIG_ALPHA_BOOK1 \ + Ruffian CONFIG_ALPHA_RUFFIAN \ Platform2000 CONFIG_ALPHA_P2K" Cabriolet if [ "$CONFIG_ALPHA_BOOK1" = "y" ] @@ -102,7 +105,8 @@ define_bool CONFIG_ALPHA_EV4 y define_bool CONFIG_ALPHA_T2 y fi -if [ "$CONFIG_ALPHA_MIATA" = "y" ] +if [ "$CONFIG_ALPHA_MIATA" = "y" -o "$CONFIG_ALPHA_LX164" = "y" \ + -o "$CONFIG_ALPHA_SX164" = "y" -o "$CONFIG_ALPHA_RUFFIAN" = "y" ] then define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y @@ -122,7 +126,8 @@ -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \ -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \ -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \ - -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" ] + -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ + -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" ] then bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM fi @@ -141,6 +146,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE fi + bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC fi bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC @@ -155,6 +161,9 @@ tristate 'Parallel port support' CONFIG_PARPORT if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT + if [ "$CONFIG_PARPORT_PC" != "n" ]; then + bool ' Support foreign hardware' CONFIG_PARPORT_OTHER + fi fi endmenu @@ -187,7 +196,7 @@ endmenu fi -source drivers/net/hamradio/Config.in +source net/ax25/Config.in mainmenu_option next_comment comment 'ISDN subsystem' @@ -223,9 +232,6 @@ source fs/nls/Config.in source drivers/char/Config.in -if [ "$CONFIG_RTC" != "n" ]; then - bool ' ARC console time' CONFIG_RTC_ARC y -fi mainmenu_option next_comment comment 'Sound' @@ -244,6 +250,12 @@ if [ "$CONFIG_PROFILE" = "y" ]; then int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Kernel FP software completion' CONFIG_MATHEMU +else + define_bool CONFIG_MATHEMU y +fi + bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ endmenu diff -ur --new-file old/linux/arch/alpha/defconfig new/linux/arch/alpha/defconfig --- old/linux/arch/alpha/defconfig Wed Sep 10 20:18:52 1997 +++ new/linux/arch/alpha/defconfig Tue Mar 10 23:43:13 1998 @@ -12,7 +12,7 @@ # CONFIG_MODULES=y # CONFIG_MODVERSIONS is not set -# CONFIG_KERNELD is not set +# CONFIG_KMOD is not set # # General setup @@ -30,13 +30,19 @@ # CONFIG_ALPHA_JENSEN is not set # CONFIG_ALPHA_NONAME is not set # CONFIG_ALPHA_MIKASA is not set +# CONFIG_ALPHA_NORITAKE is not set CONFIG_ALPHA_ALCOR=y +# CONFIG_ALPHA_MIATA is not set +# CONFIG_ALPHA_SABLE is not set +# CONFIG_ALPHA_BOOK1 is not set # CONFIG_ALPHA_P2K is not set CONFIG_PCI=y CONFIG_ALPHA_EV5=y CONFIG_ALPHA_CIA=y CONFIG_ALPHA_SRM=y +CONFIG_ALPHA_EISA=y CONFIG_TGA_CONSOLE=y +CONFIG_PCI_OLD_PROC=y CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_SYSCTL=y @@ -69,28 +75,35 @@ # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_EZ is not set +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set # CONFIG_BLK_DEV_HD is not set # # Networking options # +# 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 # CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set # CONFIG_IP_ACCT is not set +# CONFIG_IP_MASQUERADE 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 is not set # # (it is safe to leave these untouched) # -# CONFIG_INET_PCTCP is not set # CONFIG_INET_RARP is not set -CONFIG_PATH_MTU_DISCOVERY=y CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y @@ -99,7 +112,6 @@ # # CONFIG_IPX is not set # CONFIG_ATALK is not set -# CONFIG_AX25 is not set # # SCSI support @@ -120,6 +132,7 @@ # # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set # # SCSI low-level drivers @@ -138,11 +151,15 @@ # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_EATA is not set # CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX 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=y # CONFIG_SCSI_SEAGATE is not set @@ -176,13 +193,19 @@ # CONFIG_FDDI is not set # CONFIG_DLCI is not set # CONFIG_PPP is not set -# CONFIG_NET_RADIO is not set # CONFIG_SLIP is not set +# CONFIG_NET_RADIO is not set # CONFIG_TR is not set +# CONFIG_WAN_DRIVERS is not set # CONFIG_LAPBETHER is not set # CONFIG_X25_ASY is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# # ISDN subsystem # # CONFIG_ISDN is not set @@ -191,6 +214,7 @@ # CD-ROM drivers (not for SCSI or IDE/ATAPI drives) # # CONFIG_CD_NO_IDESCSI is not set +CONFIG_CDROM=y # # Filesystems @@ -198,25 +222,29 @@ # CONFIG_QUOTA is not set # CONFIG_MINIX_FS is not set CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set # CONFIG_FAT_FS is not set # CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set # CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set CONFIG_PROC_FS=y CONFIG_NFS_FS=y -# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y +# CONFIG_CODA_FS is not set # CONFIG_SMB_FS is not set -CONFIG_ISO9660_FS=y # 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_MAC_PARTITION is not set +# CONFIG_NLS is not set # # Character devices @@ -224,6 +252,7 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set CONFIG_MOUSE=y @@ -235,12 +264,18 @@ # CONFIG_PC110_PAD is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_FTAPE is not set # CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set +# CONFIG_VIDEO_DEV is not set # CONFIG_NVRAM is not set # CONFIG_JOYSTICK is not set +# CONFIG_MISC_RADIO is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set # # Sound @@ -251,4 +286,5 @@ # Kernel hacking # # CONFIG_PROFILE is not set +CONFIG_MATHEMU=y # CONFIG_MAGIC_SYSRQ is not set diff -ur --new-file old/linux/arch/alpha/kernel/Makefile new/linux/arch/alpha/kernel/Makefile --- old/linux/arch/alpha/kernel/Makefile Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/Makefile Mon Feb 23 19:25:10 1998 @@ -16,7 +16,7 @@ O_TARGET := kernel.o O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ - bios32.o ptrace.o time.o + bios32.o ptrace.o time.o fpreg.o OX_OBJS := alpha_ksyms.o @@ -35,6 +35,13 @@ ifdef CONFIG_ALPHA_T2 O_OBJS += t2.o endif +ifneq ($(CONFIG_ALPHA_PC164)$(CONFIG_ALPHA_LX164),nn) +O_OBJS += smc37c93x.o +endif +ifdef CONFIG_ALPHA_SX164 +O_OBJS += smc37c669.o +endif + all: kernel.o head.o diff -ur --new-file old/linux/arch/alpha/kernel/alpha_ksyms.c new/linux/arch/alpha/kernel/alpha_ksyms.c --- old/linux/arch/alpha/kernel/alpha_ksyms.c Mon Dec 22 18:58:21 1997 +++ new/linux/arch/alpha/kernel/alpha_ksyms.c Wed Mar 18 06:15:40 1998 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #define __KERNEL_SYSCALLS__ #include @@ -40,7 +42,7 @@ extern void __divqu (void); extern void __remqu (void); -EXPORT_SYMBOL(__alpha_bh_counter); +EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); /* platform dependent support */ @@ -56,6 +58,9 @@ EXPORT_SYMBOL(_writeb); EXPORT_SYMBOL(_writew); EXPORT_SYMBOL(_writel); +EXPORT_SYMBOL(_memcpy_fromio); +EXPORT_SYMBOL(_memcpy_toio); +EXPORT_SYMBOL(_memset_io); EXPORT_SYMBOL(insb); EXPORT_SYMBOL(insw); EXPORT_SYMBOL(insl); @@ -85,6 +90,8 @@ EXPORT_SYMBOL(hwrpb); EXPORT_SYMBOL(wrusp); EXPORT_SYMBOL(start_thread); +EXPORT_SYMBOL(alpha_read_fp_reg); +EXPORT_SYMBOL(alpha_write_fp_reg); /* In-kernel system calls. */ EXPORT_SYMBOL(__kernel_thread); @@ -101,9 +108,16 @@ /* Networking helper routines. */ EXPORT_SYMBOL(csum_tcpudp_magic); -EXPORT_SYMBOL(ip_fast_csum); EXPORT_SYMBOL(ip_compute_csum); +EXPORT_SYMBOL(ip_fast_csum); EXPORT_SYMBOL(csum_partial_copy); +EXPORT_SYMBOL(csum_partial_copy_from_user); +EXPORT_SYMBOL(csum_ipv6_magic); + +#ifdef CONFIG_MATHEMU_MODULE +extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); +EXPORT_SYMBOL(alpha_fp_emul_imprecise); +#endif /* * The following are specially called from the uaccess assembly stubs. @@ -133,3 +147,7 @@ EXPORT_SYMBOL_NOVERS(__remqu); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff -ur --new-file old/linux/arch/alpha/kernel/apecs.c new/linux/arch/alpha/kernel/apecs.c --- old/linux/arch/alpha/kernel/apecs.c Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/apecs.c Sun Jan 25 19:35:16 1998 @@ -18,6 +18,10 @@ #include #include +/* NOTE: Herein are back-to-back mb insns. They are magic. + A plausible explanation is that the i/o controler does not properly + handle the system transaction. Another involves timing. Ho hum. */ + extern struct hwrpb_struct *hwrpb; extern asmlinkage void wrmces(unsigned long mces); extern int alpha_sys_type; @@ -162,6 +166,7 @@ /* access configuration space: */ value = *(vuip)addr; mb(); + mb(); /* magic */ if (apecs_mcheck_taken) { apecs_mcheck_taken = 0; value = 0xffffffffU; @@ -242,6 +247,7 @@ /* access configuration space: */ *(vuip)addr = value; mb(); + mb(); /* magic */ apecs_mcheck_expected = 0; mb(); @@ -539,7 +545,7 @@ apecs_mcheck_expected = 0; apecs_mcheck_taken = 1; mb(); - mb(); + mb(); /* magic */ apecs_pci_clr_err(); wrmces(0x7); mb(); diff -ur --new-file old/linux/arch/alpha/kernel/bios32.c new/linux/arch/alpha/kernel/bios32.c --- old/linux/arch/alpha/kernel/bios32.c Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/bios32.c Mon Feb 23 19:25:10 1998 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #if 0 # define DBG_DEVS(args) printk args @@ -98,8 +100,11 @@ extern struct hwrpb_struct *hwrpb; /* Forward declarations for some extra fixup routines for specific hardware. */ -#ifdef CONFIG_ALPHA_PC164 -static int SMCInit(void); +#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) +extern int SMC93x_Init(void); +#endif +#ifdef CONFIG_ALPHA_SX164 +extern int SMC669_Init(void); #endif #ifdef CONFIG_ALPHA_MIATA static int es1888_init(void); @@ -174,16 +179,25 @@ struct pci_bus *bus; unsigned short cmd; -#if defined(CONFIG_ALPHA_EISA) +#ifdef CONFIG_ALPHA_EISA /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( */ - if (dev->vendor == 0x8086 && dev->device == 0x0482) { + if (dev->vendor == PCI_VENDOR_ID_INTEL && + dev->device == PCI_DEVICE_ID_INTEL_82375) { DBG_DEVS(("disable_dev: ignoring PCEB...\n")); return; } #endif +#ifdef CONFIG_ALPHA_SX164 + if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + /* FIXME: We want a symbolic device name here. */ + dev->device == 0xc693) { + DBG_DEVS(("disable_dev: ignoring CYPRESS bridge...\n")); + return; + } +#endif bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); @@ -206,6 +220,7 @@ unsigned int base, mask, size, reg; unsigned int alignto; +#ifdef CONFIG_ALPHA_EISA /* * HACK: the PCI-to-EISA bridge does not seem to identify * itself as a bridge... :-( @@ -215,6 +230,14 @@ DBG_DEVS(("layout_dev: ignoring PCEB...\n")); return; } +#endif +#ifdef CONFIG_ALPHA_SX164 + if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + dev->device == 0xc693) { + DBG_DEVS(("layout_dev: ignoring CYPRESS bridge...\n")); + return; + } +#endif bus = dev->bus; pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); @@ -729,6 +752,46 @@ 0x0000000); } } +#ifdef CONFIG_ALPHA_SX164 + /* If it the CYPRESS PCI-ISA bridge, disable IDE + interrupt routing through PCI (ie do through PIC). */ + else if (dev->vendor == PCI_VENDOR_ID_CONTAQ && + dev->device == 0xc693 && + PCI_FUNC(dev->devfn) == 0) { + pcibios_write_config_word(dev->bus->number, + dev->devfn, 0x04, 0x0007); + + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x40, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x41, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x42, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x43, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x44, 0x27); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x45, 0xe0); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x48, 0xf0); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x49, 0x40); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4a, 0x00); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4b, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4c, 0x80); + pcibios_write_config_byte(dev->bus->number, + dev->devfn, 0x4d, 0x70); + + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); + } +#endif /* SX164 */ } if (ide_base) { enable_ide(ide_base); @@ -750,7 +813,7 @@ */ static inline void eb66p_fixup(void) { - static char irq_tab[5][5] = { + static char irq_tab[5][5] __initdata = { {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */ {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */ { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */ @@ -762,7 +825,7 @@ /* - * The PC164 has 19 PCI interrupts, four from each of the four PCI + * The PC164/LX164 has 19 PCI interrupts, four from each of the four PCI * slots, the SIO, PCI/IDE, and USB. * * Each of the interrupts can be individually masked. This is @@ -803,10 +866,10 @@ * */ -#ifdef CONFIG_ALPHA_PC164 +#if defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) static inline void alphapc164_fixup(void) { - static char irq_tab[7][5] = { + static char irq_tab[7][5] __initdata = { /*INT INTA INTB INTC INTD */ { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */ { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */ @@ -818,7 +881,7 @@ }; common_fixup(5, 11, 5, irq_tab, 0); - SMCInit(); + SMC93x_Init(); } #endif @@ -837,7 +900,7 @@ */ static inline void cabriolet_fixup(void) { - static char irq_tab[5][5] = { + static char irq_tab[5][5] __initdata = { { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */ { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */ { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */ @@ -893,7 +956,7 @@ */ static inline void eb66_and_eb64p_fixup(void) { - static char irq_tab[5][5] = { + static char irq_tab[5][5] __initdata = { {16+7, 16+7, 16+7, 16+7, 16+7}, /* IdSel 5, slot ?, ?? */ {16+0, 16+0, 16+2, 16+4, 16+9}, /* IdSel 6, slot ?, ?? */ {16+1, 16+1, 16+3, 16+8, 16+10}, /* IdSel 7, slot ?, ?? */ @@ -942,7 +1005,7 @@ */ static inline void mikasa_fixup(void) { - static char irq_tab[8][5] = { + static char irq_tab[8][5] __initdata = { /*INT INTA INTB INTC INTD */ {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 17, SCSI */ { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ @@ -1013,7 +1076,7 @@ */ static inline void noritake_fixup(void) { - static char irq_tab[13][5] = { + static char irq_tab[13][5] __initdata = { /*INT INTA INTB INTC INTD */ { -1, -1, -1, -1, -1}, /* IdSel 18, PCEB */ { -1, -1, -1, -1, -1}, /* IdSel 19, PPB */ @@ -1077,7 +1140,7 @@ */ static inline void alcor_fixup(void) { - static char irq_tab[6][5] = { + static char irq_tab[6][5] __initdata = { /*INT INTA INTB INTC INTD */ { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ {16+16, 16+16, 16+17, 16+18, 16+19}, /* IdSel 19, slot 3 */ @@ -1132,7 +1195,7 @@ */ static inline void xlt_fixup(void) { - static char irq_tab[7][5] = { + static char irq_tab[7][5] __initdata = { /*INT INTA INTB INTC INTD */ {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */ { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ @@ -1194,13 +1257,16 @@ * above for PCI interrupts. The IRQ relates to which bit the interrupt * comes in on. This makes interrupt processing much easier. */ -/* NOTE: the IRQ assignments below are arbitrary, but need to be consistent - with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables - in irq.c +/* + * NOTE: the IRQ assignments below are arbitrary, but need to be consistent + * with the values in the sable_irq_to_mask[] and sable_mask_to_irq[] tables + * in irq.c */ + +#ifdef CONFIG_ALPHA_SABLE static inline void sable_fixup(void) { - static char irq_tab[9][5] = { + static char irq_tab[9][5] __initdata = { /*INT INTA INTB INTC INTD */ { 32+0, 32+0, 32+0, 32+0, 32+0}, /* IdSel 0, TULIP */ { 32+1, 32+1, 32+1, 32+1, 32+1}, /* IdSel 1, SCSI */ @@ -1214,6 +1280,7 @@ }; common_fixup(0, 8, 5, irq_tab, 0); } +#endif /* * Fixup configuration for MIATA (EV56+PYXIS) @@ -1282,7 +1349,7 @@ #ifdef CONFIG_ALPHA_MIATA static inline void miata_fixup(void) { - static char irq_tab[18][5] = { + static char irq_tab[18][5] __initdata = { /*INT INTA INTB INTC INTD */ {16+ 8, 16+ 8, 16+ 8, 16+ 8, 16+ 8}, /* IdSel 14, DC21142 */ { -1, -1, -1, -1, -1}, /* IdSel 15, EIDE */ @@ -1311,6 +1378,64 @@ #endif /* + * Fixup configuration for SX164 (PCA56+PYXIS) + * + * Summary @ PYXIS_INT_REQ: + * Bit Meaning + * 0 RSVD + * 1 NMI + * 2 Halt/Reset switch + * 3 MBZ + * 4 RAZ + * 5 RAZ + * 6 Interval timer (RTC) + * 7 PCI-ISA Bridge + * 8 Interrupt Line A from slot 3 + * 9 Interrupt Line A from slot 2 + *10 Interrupt Line A from slot 1 + *11 Interrupt Line A from slot 0 + *12 Interrupt Line B from slot 3 + *13 Interrupt Line B from slot 2 + *14 Interrupt Line B from slot 1 + *15 Interrupt line B from slot 0 + *16 Interrupt Line C from slot 3 + + *17 Interrupt Line C from slot 2 + *18 Interrupt Line C from slot 1 + *19 Interrupt Line C from slot 0 + *20 Interrupt Line D from slot 3 + *21 Interrupt Line D from slot 2 + *22 Interrupt Line D from slot 1 + *23 Interrupt Line D from slot 0 + * + * IdSel + * 5 32 bit PCI option slot 2 + * 6 64 bit PCI option slot 0 + * 7 64 bit PCI option slot 1 + * 8 Cypress I/O + * 9 32 bit PCI option slot 3 + * + */ + +#ifdef CONFIG_ALPHA_SX164 +static inline void sx164_fixup(void) +{ + static char irq_tab[5][5] __initdata = { + /*INT INTA INTB INTC INTD */ + { 16+ 9, 16+ 9, 16+13, 16+17, 16+21}, /* IdSel 5 slot 2 J17 */ + { 16+11, 16+11, 16+15, 16+19, 16+23}, /* IdSel 6 slot 0 J19 */ + { 16+10, 16+10, 16+14, 16+18, 16+22}, /* IdSel 7 slot 1 J18 */ + { -1, -1, -1, -1, -1}, /* IdSel 8 SIO */ + { 16+ 8, 16+ 8, 16+12, 16+16, 16+20} /* IdSel 9 slot 3 J15 */ + }; + + common_fixup(5, 9, 5, irq_tab, 0); + + SMC669_Init(); +} +#endif + +/* * Fixup configuration for all boards that route the PCI interrupts * through the SIO PCI/ISA bridge. This includes Noname (AXPpci33), * Avanti (AlphaStation) and Kenetics's Platform 2000. @@ -1336,7 +1461,7 @@ * that they use the default INTA line, if they are interrupt * driven at all). */ - static const char pirq_tab[][5] = { + static const char pirq_tab[][5] __initdata = { #ifdef CONFIG_ALPHA_P2K { 0, 0, -1, -1, -1}, /* idsel 6 (53c810) */ {-1, -1, -1, -1, -1}, /* idsel 7 (SIO: PCI/ISA bridge) */ @@ -1560,9 +1685,10 @@ extern void tga_console_init(void); #endif /* CONFIG_TGA_CONSOLE */ -unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end) +unsigned long __init +pcibios_fixup(unsigned long mem_start, unsigned long mem_end) { -#if PCI_MODIFY +#if PCI_MODIFY && !defined(CONFIG_ALPHA_RUFFIAN) /* * Scan the tree, allocating PCI memory and I/O space. */ @@ -1577,7 +1703,7 @@ sio_fixup(); #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB164) cabriolet_fixup(); -#elif defined(CONFIG_ALPHA_PC164) +#elif defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164) alphapc164_fixup(); #elif defined(CONFIG_ALPHA_EB66P) eb66p_fixup(); @@ -1597,6 +1723,10 @@ miata_fixup(); #elif defined(CONFIG_ALPHA_NORITAKE) noritake_fixup(); +#elif defined(CONFIG_ALPHA_SX164) + sx164_fixup(); +#elif defined(CONFIG_ALPHA_RUFFIAN) + /* no fixup needed */ #else # error "You must tell me what kind of platform you want." #endif @@ -1702,251 +1832,12 @@ } -#ifdef CONFIG_ALPHA_PC164 -/* device "activate" register contents */ -#define DEVICE_ON 1 -#define DEVICE_OFF 0 - -/* configuration on/off keys */ -#define CONFIG_ON_KEY 0x55 -#define CONFIG_OFF_KEY 0xaa - -/* configuration space device definitions */ -#define FDC 0 -#define IDE1 1 -#define IDE2 2 -#define PARP 3 -#define SER1 4 -#define SER2 5 -#define RTCL 6 -#define KYBD 7 -#define AUXIO 8 - -/* Chip register offsets from base */ -#define CONFIG_CONTROL 0x02 -#define INDEX_ADDRESS 0x03 -#define LOGICAL_DEVICE_NUMBER 0x07 -#define DEVICE_ID 0x20 -#define DEVICE_REV 0x21 -#define POWER_CONTROL 0x22 -#define POWER_MGMT 0x23 -#define OSC 0x24 - -#define ACTIVATE 0x30 -#define ADDR_HI 0x60 -#define ADDR_LO 0x61 -#define INTERRUPT_SEL 0x70 -#define INTERRUPT_SEL_2 0x72 /* KYBD/MOUS only */ -#define DMA_CHANNEL_SEL 0x74 /* FDC/PARP only */ - -#define FDD_MODE_REGISTER 0x90 -#define FDD_OPTION_REGISTER 0x91 - -/* values that we read back that are expected ... */ -#define VALID_DEVICE_ID 2 - -/* default device addresses */ -#define KYBD_INTERRUPT 1 -#define MOUS_INTERRUPT 12 -#define COM2_BASE 0x2f8 -#define COM2_INTERRUPT 3 -#define COM1_BASE 0x3f8 -#define COM1_INTERRUPT 4 -#define PARP_BASE 0x3bc -#define PARP_INTERRUPT 7 - -#define SMC_DEBUG 0 - -static unsigned long SMCConfigState(unsigned long baseAddr) -{ - unsigned char devId; - unsigned char devRev; - - unsigned long configPort; - unsigned long indexPort; - unsigned long dataPort; - - configPort = indexPort = baseAddr; - dataPort = configPort + 1; - - outb(CONFIG_ON_KEY, configPort); - outb(CONFIG_ON_KEY, configPort); - outb(DEVICE_ID, indexPort); - devId = inb(dataPort); - if ( devId == VALID_DEVICE_ID ) { - outb(DEVICE_REV, indexPort); - devRev = inb(dataPort); - } - else { - baseAddr = 0; - } - return baseAddr; -} - -static void SMCRunState(unsigned long baseAddr) -{ - outb(CONFIG_OFF_KEY, baseAddr); -} - -static unsigned long SMCDetectUltraIO(void) -{ - unsigned long baseAddr; - - baseAddr = 0x3F0; - if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) { - return( baseAddr ); - } - baseAddr = 0x370; - if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) { - return( baseAddr ); - } - return( ( unsigned long )0 ); -} - -static void SMCEnableDevice(unsigned long baseAddr, - unsigned long device, - unsigned long portaddr, - unsigned long interrupt) -{ - unsigned long indexPort; - unsigned long dataPort; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(device, dataPort); - - outb(ADDR_LO, indexPort); - outb(( portaddr & 0xFF ), dataPort); - - outb(ADDR_HI, indexPort); - outb((portaddr >> 8) & 0xFF, dataPort); - - outb(INTERRUPT_SEL, indexPort); - outb(interrupt, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); -} - -static void SMCEnableKYBD(unsigned long baseAddr) -{ - unsigned long indexPort; - unsigned long dataPort; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(KYBD, dataPort); - - outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ - outb(KYBD_INTERRUPT, dataPort); - - outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */ - outb(MOUS_INTERRUPT, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); -} - -static void SMCEnableFDC(unsigned long baseAddr) -{ - unsigned long indexPort; - unsigned long dataPort; - - unsigned char oldValue; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(LOGICAL_DEVICE_NUMBER, indexPort); - outb(FDC, dataPort); - - outb(FDD_MODE_REGISTER, indexPort); - oldValue = inb(dataPort); - - oldValue |= 0x0E; /* Enable burst mode */ - outb(oldValue, dataPort); - - outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ - outb(0x06, dataPort ); - - outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */ - outb(0x02, dataPort); - - outb(ACTIVATE, indexPort); - outb(DEVICE_ON, dataPort); -} - -#if SMC_DEBUG -static void SMCReportDeviceStatus(unsigned long baseAddr) -{ - unsigned long indexPort; - unsigned long dataPort; - unsigned char currentControl; - - indexPort = baseAddr; - dataPort = baseAddr + 1; - - outb(POWER_CONTROL, indexPort); - currentControl = inb(dataPort); - - printk(currentControl & (1 << FDC) - ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n"); - printk(currentControl & (1 << IDE1) - ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n"); - printk(currentControl & (1 << IDE2) - ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n"); - printk(currentControl & (1 << PARP) - ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n"); - printk(currentControl & (1 << SER1) - ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n"); - printk(currentControl & (1 << SER2) - ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n"); - - printk( "\n" ); -} -#endif - -static int SMCInit(void) -{ - unsigned long SMCUltraBase; - - if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) { - printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", - SMCUltraBase); -#if SMC_DEBUG - SMCReportDeviceStatus(SMCUltraBase); -#endif - SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT); - SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT); - SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT); - /* On PC164, IDE on the SMC is not enabled; - CMD646 (PCI) on MB */ - SMCEnableKYBD(SMCUltraBase); - SMCEnableFDC(SMCUltraBase); -#if SMC_DEBUG - SMCReportDeviceStatus(SMCUltraBase); -#endif - SMCRunState(SMCUltraBase); - return 1; - } - else { -#if SMC_DEBUG - printk("No SMC FDC37C93X Ultra I/O Controller found\n"); -#endif - return 0; - } -} -#endif /* CONFIG_ALPHA_PC164 */ - #ifdef CONFIG_ALPHA_MIATA /* * Init the built-in ES1888 sound chip (SB16 compatible) */ -static int es1888_init(void) +static int __init +es1888_init(void) { /* Sequence of IO reads to init the audio controller */ inb(0x0229); diff -ur --new-file old/linux/arch/alpha/kernel/cia.c new/linux/arch/alpha/kernel/cia.c --- old/linux/arch/alpha/kernel/cia.c Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/cia.c Sun Jan 25 19:35:16 1998 @@ -17,6 +17,10 @@ #include #include +/* NOTE: Herein are back-to-back mb insns. They are magic. + A plausible explanation is that the i/o controler does not properly + handle the system transaction. Another involves timing. Ho hum. */ + extern struct hwrpb_struct *hwrpb; extern asmlinkage void wrmces(unsigned long mces); extern int alpha_sys_type; @@ -170,6 +174,7 @@ /* access configuration space: */ value = *(vuip)addr; mb(); + mb(); /* magic */ if (CIA_mcheck_taken) { CIA_mcheck_taken = 0; value = 0xffffffffU; @@ -244,6 +249,7 @@ /* access configuration space: */ *(vuip)addr = value; mb(); + mb(); /* magic */ CIA_mcheck_expected = 0; mb(); @@ -555,12 +561,13 @@ * ignore the machine check. */ mb(); + mb(); /* magic */ if (CIA_mcheck_expected) { DBGM(("CIA machine check expected\n")); CIA_mcheck_expected = 0; CIA_mcheck_taken = 1; mb(); - mb(); + mb(); /* magic */ draina(); cia_pci_clr_err(); wrmces(0x7); 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 Sat Jan 10 20:58:12 1998 +++ new/linux/arch/alpha/kernel/entry.S Sun Mar 1 19:23:16 1998 @@ -10,7 +10,7 @@ #define rti .long PAL_rti #define SIGCHLD 20 -#define NR_SYSCALLS 360 +#define NR_SYSCALLS 370 #define osf_vfork sys_fork /* @@ -318,6 +318,7 @@ stt $f29,296($30) stt $f30,304($30) stt $f0,312($30) # save fpcr in slot of $f31 + ldt $f0,64($30) # don't let "do_switch_stack" change any fp state. ret $31,($1),1 .end do_switch_stack @@ -529,7 +530,7 @@ lda $4,NR_SYSCALLS($31) stq $16,SP_OFF+24($30) lda $5,sys_call_table - lda $27,alpha_ni_syscall + lda $27,sys_ni_syscall cmpult $0,$4,$4 ldq $3,TASK_FLAGS($8) stq $17,SP_OFF+32($30) @@ -854,7 +855,7 @@ .quad alpha_ni_syscall .quad alpha_ni_syscall /* 110 */ .quad sys_sigsuspend - .quad alpha_ni_syscall + .quad sys_ni_syscall .quad sys_recvmsg .quad sys_sendmsg .quad alpha_ni_syscall /* 115 */ @@ -950,7 +951,7 @@ .quad sys_semget /* 205 */ .quad sys_semop .quad osf_utsname - .quad alpha_ni_syscall + .quad sys_lchown .quad osf_shmat .quad sys_shmctl /* 210 */ .quad sys_shmdt @@ -1046,7 +1047,7 @@ .quad sys_bdflush /* 300 */ .quad sys_sethae .quad sys_mount - .quad sys_adjtimex + .quad sys_old_adjtimex .quad sys_swapoff .quad sys_getdents /* 305 */ .quad alpha_create_module @@ -1081,7 +1082,7 @@ .quad sys_sched_get_priority_max /* 335 */ .quad sys_sched_get_priority_min .quad sys_sched_rr_get_interval - .quad alpha_ni_syscall /* sys_afs_syscall */ + .quad sys_ni_syscall /* sys_afs_syscall */ .quad sys_newuname .quad sys_nanosleep /* 340 */ .quad sys_mremap @@ -1101,8 +1102,15 @@ .quad sys_rt_sigtimedwait /* 355 */ .quad sys_rt_sigqueueinfo .quad sys_rt_sigsuspend - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall - .quad alpha_ni_syscall /* 360 */ + .quad sys_select + .quad sys_gettimeofday + .quad sys_settimeofday /* 360 */ + .quad sys_getitimer + .quad sys_setitimer + .quad sys_utimes + .quad sys_getrusage + .quad sys_wait4 /* 365 */ + .quad sys_adjtimex + .quad sys_ni_syscall + .quad sys_ni_syscall + .quad sys_ni_syscall /* 369 */ diff -ur --new-file old/linux/arch/alpha/kernel/fpreg.c new/linux/arch/alpha/kernel/fpreg.c --- old/linux/arch/alpha/kernel/fpreg.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/kernel/fpreg.c Thu Feb 12 22:31:28 1998 @@ -0,0 +1,104 @@ +/* + * kernel/fpreg.c + * + * (C) Copyright 1998 Linus Torvalds + */ + +unsigned long +alpha_read_fp_reg (unsigned long reg) +{ + unsigned long r; + + switch (reg) { + case 0: asm ("stt $f0,%0" : "m="(r)); break; + case 1: asm ("stt $f1,%0" : "m="(r)); break; + case 2: asm ("stt $f2,%0" : "m="(r)); break; + case 3: asm ("stt $f3,%0" : "m="(r)); break; + case 4: asm ("stt $f4,%0" : "m="(r)); break; + case 5: asm ("stt $f5,%0" : "m="(r)); break; + case 6: asm ("stt $f6,%0" : "m="(r)); break; + case 7: asm ("stt $f7,%0" : "m="(r)); break; + case 8: asm ("stt $f8,%0" : "m="(r)); break; + case 9: asm ("stt $f9,%0" : "m="(r)); break; + case 10: asm ("stt $f10,%0" : "m="(r)); break; + case 11: asm ("stt $f11,%0" : "m="(r)); break; + case 12: asm ("stt $f12,%0" : "m="(r)); break; + case 13: asm ("stt $f13,%0" : "m="(r)); break; + case 14: asm ("stt $f14,%0" : "m="(r)); break; + case 15: asm ("stt $f15,%0" : "m="(r)); break; + case 16: asm ("stt $f16,%0" : "m="(r)); break; + case 17: asm ("stt $f17,%0" : "m="(r)); break; + case 18: asm ("stt $f18,%0" : "m="(r)); break; + case 19: asm ("stt $f19,%0" : "m="(r)); break; + case 20: asm ("stt $f20,%0" : "m="(r)); break; + case 21: asm ("stt $f21,%0" : "m="(r)); break; + case 22: asm ("stt $f22,%0" : "m="(r)); break; + case 23: asm ("stt $f23,%0" : "m="(r)); break; + case 24: asm ("stt $f24,%0" : "m="(r)); break; + case 25: asm ("stt $f25,%0" : "m="(r)); break; + case 26: asm ("stt $f26,%0" : "m="(r)); break; + case 27: asm ("stt $f27,%0" : "m="(r)); break; + case 28: asm ("stt $f28,%0" : "m="(r)); break; + case 29: asm ("stt $f29,%0" : "m="(r)); break; + case 30: asm ("stt $f30,%0" : "m="(r)); break; + case 31: asm ("stt $f31,%0" : "m="(r)); break; + default: + break; + } + return r; +} + +#if 1 +/* + * This is IMHO the better way of implementing LDT(). But it + * has the disadvantage that gcc 2.7.0 refuses to compile it + * (invalid operand constraints), so instead, we use the uglier + * macro below. + */ +# define LDT(reg,val) \ + asm volatile ("ldt $f"#reg",%0" : : "m"(val)); +#else +# define LDT(reg,val) \ + asm volatile ("ldt $f"#reg",0(%0)" : : "r"(&val)); +#endif + +void +alpha_write_fp_reg (unsigned long reg, unsigned long val) +{ + switch (reg) { + case 0: LDT( 0, val); break; + case 1: LDT( 1, val); break; + case 2: LDT( 2, val); break; + case 3: LDT( 3, val); break; + case 4: LDT( 4, val); break; + case 5: LDT( 5, val); break; + case 6: LDT( 6, val); break; + case 7: LDT( 7, val); break; + case 8: LDT( 8, val); break; + case 9: LDT( 9, val); break; + case 10: LDT(10, val); break; + case 11: LDT(11, val); break; + case 12: LDT(12, val); break; + case 13: LDT(13, val); break; + case 14: LDT(14, val); break; + case 15: LDT(15, val); break; + case 16: LDT(16, val); break; + case 17: LDT(17, val); break; + case 18: LDT(18, val); break; + case 19: LDT(19, val); break; + case 20: LDT(20, val); break; + case 21: LDT(21, val); break; + case 22: LDT(22, val); break; + case 23: LDT(23, val); break; + case 24: LDT(24, val); break; + case 25: LDT(25, val); break; + case 26: LDT(26, val); break; + case 27: LDT(27, val); break; + case 28: LDT(28, val); break; + case 29: LDT(29, val); break; + case 30: LDT(30, val); break; + case 31: LDT(31, val); break; + default: + break; + } +} diff -ur --new-file old/linux/arch/alpha/kernel/head.S new/linux/arch/alpha/kernel/head.S --- old/linux/arch/alpha/kernel/head.S Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/head.S Thu Feb 12 22:31:28 1998 @@ -121,37 +121,3 @@ call_pal PAL_cserve ret ($26) .end cserve_dis - - # - # The following two functions don't need trapb/excb instructions - # around the mf_fpcr/mt_fpcr instructions because (a) the kernel - # never generates arithmetic faults and (b) call_pal instructions - # are implied trap barriers. - # - .align 3 - .globl rdfpcr - .ent rdfpcr -rdfpcr: - lda $30,-0x10($30) - stt $f0,0($30) - mf_fpcr $f0 - stt $f0,8($30) - ldt $f0,0($30) - ldq $0,8($30) - lda $30,0x10($30) - ret ($26) - .end rdfpcr - - .align 3 - .globl wrfpcr - .ent wrfpcr -wrfpcr: - lda $30,-0x10($30) - stt $f0,0($30) - stq $16,8($30) - ldt $f0,8($30) - mt_fpcr $f0 - ldt $f0,0($30) - lda $30,0x10($30) - ret ($26) - .end wrfpcr diff -ur --new-file old/linux/arch/alpha/kernel/irq.c new/linux/arch/alpha/kernel/irq.c --- old/linux/arch/alpha/kernel/irq.c Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/irq.c Thu Feb 26 20:05:49 1998 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,9 @@ #elif defined(CONFIG_ALPHA_ALCOR) /* always mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade: */ # define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~0xfff000000001UL) +#elif defined(CONFIG_ALPHA_RUFFIAN) + /* must leave timer irq 0 in the mask */ +# define PROBE_MASK ((1UL << NR_IRQS) - 1) #else /* always mask out unused timer irq 0: */ # define PROBE_MASK (((1UL << NR_IRQS) - 1) & ~1UL) @@ -210,6 +214,53 @@ } } +#ifdef CONFIG_ALPHA_RUFFIAN +static inline void +ruffian_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + case 16 ... 47: + /* Note inverted sense of mask bits: */ + /* Make CERTAIN none of the bogus ints get enabled... */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & 0x00000000ffffffbfUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} +#endif + +#ifdef CONFIG_ALPHA_SX164 +static inline void +sx164_update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { + case 16 ... 39: + /* Make CERTAIN none of the bogus ints get enabled */ + *(vulp)PYXIS_INT_MASK = + ~((long)mask >> 16) & ~0x000000000000003bUL; + mb(); + /* ... and read it back to make sure it got written. */ + *(vulp)PYXIS_INT_MASK; + break; + case 8 ... 15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + } +} +#endif + /* Unlabeled mechanisms based on the number of irqs. Someone should probably document and name these. */ @@ -262,7 +313,8 @@ } } -#if defined(CONFIG_ALPHA_PC164) && defined(CONFIG_ALPHA_SRM) +#if (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \ + && defined(CONFIG_ALPHA_SRM) /* * On the pc164, we cannot take over the IRQs from the SRM, * so we call down to do our dirty work. Too bad the SRM @@ -313,6 +365,10 @@ alcor_and_xlt_update_hw(irq, mask); #elif defined(CONFIG_ALPHA_MIKASA) mikasa_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_SX164) + sx164_update_hw(irq, mask); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_update_hw(irq, mask); #elif NR_IRQS == 33 update_hw_33(irq, mask); #elif NR_IRQS == 32 @@ -355,7 +411,7 @@ unmask_irq(IRQ_TO_MASK(irq_nr)); restore_flags(flags); } -#endif /* PC164 && SRM */ +#endif /* (PC164 || LX164) && SRM */ /* * Initial irq handlers. @@ -373,7 +429,7 @@ if (!action) continue; len += sprintf(buf+len, "%2d: %10u %c %s", - i, kstat.interrupts[i], + i, kstat.irqs[0][i], (action->flags & SA_INTERRUPT) ? '+' : ' ', action->name); for (action=action->next; action; action = action->next) { @@ -404,9 +460,23 @@ outb(0xE0 | 4, 0x534); /* slave 2 */ break; } -#else /* CONFIG_ALPHA_SABLE */ +#elif defined(CONFIG_ALPHA_RUFFIAN) if (irq < 16) { - /* ACK the interrupt making it the lowest priority */ + /* Ack PYXIS ISA interrupt. */ + *(vulp)PYXIS_INT_REQ = 1 << 7; + mb(); + if (irq > 7) { + outb(0x20, 0xa0); + } + outb(0x20, 0x20); + } else { + /* Ack PYXIS interrupt. */ + *(vulp)PYXIS_INT_REQ = (1UL << (irq - 16)); + mb(); + } +#else + if (irq < 16) { + /* Ack the interrupt making it the lowest priority */ /* First the slave .. */ if (irq > 7) { outb(0xE0 | (irq - 8), 0xa0); @@ -418,9 +488,19 @@ /* on ALCOR/XLT, need to dismiss interrupt via GRU */ *(vuip)GRU_INT_CLEAR = 0x80000000; mb(); *(vuip)GRU_INT_CLEAR = 0x00000000; mb(); -#endif /* ALCOR || XLT */ +#endif } -#endif /* CONFIG_ALPHA_SABLE */ +#endif +} + +int check_irq(unsigned int irq) +{ + struct irqaction **p; + + p = irq_action + irq; + if (*p == NULL) + return 0; + return -EBUSY; } int request_irq(unsigned int irq, @@ -524,7 +604,7 @@ } unsigned int local_irq_count[NR_CPUS]; -atomic_t __alpha_bh_counter; +unsigned int local_bh_count[NR_CPUS]; #ifdef __SMP__ #error "Me no hablo Alpha SMP" @@ -567,7 +647,7 @@ int cpu = smp_processor_id(); irq_enter(cpu, irq); - kstat.interrupts[irq]++; + kstat.irqs[0][irq] += 1; if (!action) { unexpected_irq(irq, regs); } else { @@ -590,7 +670,7 @@ } irq_enter(cpu, irq); - kstat.interrupts[irq]++; + kstat.irqs[0][irq] += 1; action = irq_action[irq]; /* * For normal interrupts, we mask it out, and then ACK it. @@ -820,7 +900,7 @@ restore_flags(flags); } -#if defined(CONFIG_ALPHA_MIATA) +#if defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164) /* We have to conditionally compile this because of PYXIS_xxx symbols */ static inline void miata_device_interrupt(unsigned long vector, struct pt_regs *regs) @@ -840,15 +920,19 @@ *(vulp)PYXIS_INT_MASK, inb(0x20) | (inb(0xA0) << 8)); #endif -#if 1 - /* - * For now, AND off any bits we are not interested in: - * HALT (2), timer (6), ISA Bridge (7), 21142/3 (8) - * then all the PCI slots/INTXs (12-31). - */ + /* For now, AND off any bits we are not interested in. */ +#if defined(CONFIG_ALPHA_MIATA) + /* HALT (2), timer (6), ISA Bridge (7), 21142/3 (8), + then all the PCI slots/INTXs (12-31). */ /* Maybe HALT should only be used for SRM console boots? */ pld &= 0x00000000fffff1c4UL; #endif +#if defined(CONFIG_ALPHA_SX164) + /* HALT (2), timer (6), ISA Bridge (7), + then all the PCI slots/INTXs (8-23). */ + /* HALT should only be used for SRM console boots. */ + pld &= 0x0000000000ffffc0UL; +#endif /* * Now for every possible bit set, work through them and call @@ -869,7 +953,7 @@ } restore_flags(flags); } -#endif /* MIATA */ +#endif /* MIATA || SX164 */ static inline void noritake_device_interrupt(unsigned long vector, struct pt_regs *regs) @@ -907,6 +991,69 @@ restore_flags(flags); } +#if defined(CONFIG_ALPHA_RUFFIAN) +static inline void +ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* Read the interrupt summary register of PYXIS */ + pld = *(vulp)PYXIS_INT_REQ; + + /* For now, AND off any bits we are not interested in: + * HALT (2), timer (6), ISA Bridge (7), 21142 (8) + * then all the PCI slots/INTXs (12-31) + * flash(5) :DWH: + */ + pld &= 0x00000000ffffff9fUL; + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + + if (i == 7) { + /* Copy this bit from isa_device_interrupt cause + we need to hook into int 0 for the timer. I + refuse to soil device_interrupt with ifdefs. */ + + /* Generate a PCI interrupt acknowledge cycle. + The PIC will respond with the interrupt + vector of the highest priority interrupt + that is pending. The PALcode sets up the + interrupts vectors such that irq level L + generates vector L. */ + + unsigned int j = *(vuip)PYXIS_IACK_SC & 0xff; + if (j == 7 && !(inb(0x20) & 0x80)) { + /* It's only a passive release... */ + } else if (j == 0) { + timer_interrupt(regs); + ack_irq(0); + } else { + device_interrupt(j, j, regs); + } + } else { + device_interrupt(16 + i, 16 + i, regs); + } + + *(vulp)PYXIS_INT_REQ = 1UL << i; + mb(); + *(vulp)PYXIS_INT_REQ; + } + + restore_flags(flags); +} +#endif /* RUFFIAN */ + #endif /* CONFIG_PCI */ /* @@ -1050,7 +1197,6 @@ */ int probe_irq_off(unsigned long irqs) { - unsigned long delay; int i; irqs &= irq_mask; @@ -1110,16 +1256,18 @@ #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \ defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM) srm_device_interrupt(vector, ®s); -#elif defined(CONFIG_ALPHA_MIATA) +#elif defined(CONFIG_ALPHA_MIATA) || defined(CONFIG_ALPHA_SX164) miata_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_NORITAKE) noritake_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) alcor_and_xlt_device_interrupt(vector, ®s); -#elif NR_IRQS == 33 - cabriolet_and_eb66p_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_device_interrupt(vector, ®s); #elif defined(CONFIG_ALPHA_MIKASA) mikasa_device_interrupt(vector, ®s); +#elif NR_IRQS == 33 + cabriolet_and_eb66p_device_interrupt(vector, ®s); #elif NR_IRQS == 32 eb66_and_eb64p_device_interrupt(vector, ®s); #elif NR_IRQS == 16 @@ -1145,6 +1293,57 @@ outb(0x44, 0x535); /* enable cascades in master */ } +#ifdef CONFIG_ALPHA_SX164 +static inline void sx164_init_IRQ(void) +{ + /* note invert on MASK bits */ + *(vulp)PYXIS_INT_MASK = ~((long)irq_mask >> 16); mb(); +#if 0 + *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */ + *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */ +#endif + enable_irq(16 + 6); /* enable timer */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(2); /* enable cascade */ +} +#endif /* SX164 */ + +#ifdef CONFIG_ALPHA_RUFFIAN +static inline void ruffian_init_IRQ(void) +{ + /* invert 6&7 for i82371 */ + *(vulp)PYXIS_INT_HILO = 0x000000c0UL; mb(); + *(vulp)PYXIS_INT_CNFG = 0x00002064UL; mb(); /* all clear */ + *(vulp)PYXIS_INT_MASK = 0x00000000UL; mb(); + *(vulp)PYXIS_INT_REQ = 0xffffffffUL; mb(); + + outb(0x11,0xA0); + outb(0x08,0xA1); + outb(0x02,0xA1); + outb(0x01,0xA1); + outb(0xFF,0xA1); + + outb(0x11,0x20); + outb(0x00,0x21); + outb(0x04,0x21); + outb(0x01,0x21); + outb(0xFF,0x21); + + /* Send -INTA pulses to clear any pending interrupts ...*/ + *(vuip) IACK_SC; + + /* Finish writing the 82C59A PIC Operation Control Words */ + outb(0x20,0xA0); + outb(0x20,0x20); + + /* Turn on the interrupt controller, the timer interrupt */ + enable_irq(16 + 7); /* enable ISA PIC cascade */ + enable_irq(0); /* enable timer */ + enable_irq(2); /* enable 2nd PIC cascade */ +} +#endif /* RUFFIAN */ + + #ifdef CONFIG_ALPHA_MIATA static inline void miata_init_IRQ(void) { @@ -1210,27 +1409,36 @@ enable_irq(2); /* enable cascade */ } -void init_IRQ(void) +void __init +init_IRQ(void) { wrent(entInt, 0); dma_outb(0, DMA1_RESET_REG); dma_outb(0, DMA2_RESET_REG); +#ifndef CONFIG_ALPHA_SX164 dma_outb(0, DMA1_CLR_MASK_REG); + /* We need to figure out why this fails on the SX164. */ dma_outb(0, DMA2_CLR_MASK_REG); +#endif #if defined(CONFIG_ALPHA_SABLE) sable_init_IRQ(); #elif defined(CONFIG_ALPHA_MIATA) miata_init_IRQ(); +#elif defined(CONFIG_ALPHA_SX164) + sx164_init_IRQ(); #elif defined(CONFIG_ALPHA_NORITAKE) noritake_init_IRQ(); #elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) alcor_and_xlt_init_IRQ(); -#elif defined(CONFIG_ALPHA_PC164) && defined(CONFIG_ALPHA_SRM) +#elif (defined(CONFIG_ALPHA_PC164) || defined(CONFIG_ALPHA_LX164)) \ + && defined(CONFIG_ALPHA_SRM) /* Disable all the PCI interrupts? Otherwise, everthing was done by SRM already. */ #elif defined(CONFIG_ALPHA_MIKASA) mikasa_init_IRQ(); +#elif defined(CONFIG_ALPHA_RUFFIAN) + ruffian_init_IRQ(); #elif NR_IRQS == 33 init_IRQ_33(); #elif NR_IRQS == 32 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 Mon Jan 12 23:49:36 1998 +++ new/linux/arch/alpha/kernel/osf_sys.c Wed Feb 25 03:04:07 1998 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -246,7 +247,7 @@ unsigned long ret = -EBADF; lock_kernel(); - if (flags & (MAP_HASSEMAPHORE | MAP_INHERIT | MAP_UNALIGNED)) + if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) printk("%s: unimplemented OSF mmap flags %04lx\n", current->comm, flags); if (!(flags & MAP_ANONYMOUS)) { if (fd >= NR_OPEN || !(file = current->files->fd[fd])) @@ -871,7 +872,7 @@ 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); + fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16); wrfpcr(fpcr); return 0; @@ -925,6 +926,7 @@ extern int do_setitimer(int which, struct itimerval *, struct itimerval *); asmlinkage int sys_utimes(char *, struct timeval *); extern int sys_wait4(pid_t, int *, int, struct rusage *); +extern int do_adjtimex(struct timex *); struct timeval32 { @@ -1269,4 +1271,58 @@ return 0; fault: return -EFAULT; +} + + +struct timex32 { + unsigned int modes; /* mode selector */ + long offset; /* time offset (usec) */ + long freq; /* frequency offset (scaled ppm) */ + long maxerror; /* maximum error (usec) */ + long esterror; /* estimated error (usec) */ + int status; /* clock command/status */ + long constant; /* pll time constant */ + long precision; /* clock precision (usec) (read only) */ + long tolerance; /* clock frequency tolerance (ppm) + * (read only) + */ + struct timeval32 time; /* (read only) */ + long tick; /* (modified) usecs between clock ticks */ + + long ppsfreq; /* pps frequency (scaled ppm) (ro) */ + long jitter; /* pps jitter (us) (ro) */ + int shift; /* interval duration (s) (shift) (ro) */ + long stabil; /* pps stability (scaled ppm) (ro) */ + long jitcnt; /* jitter limit exceeded (ro) */ + long calcnt; /* calibration intervals (ro) */ + long errcnt; /* calibration errors (ro) */ + long stbcnt; /* stability limit exceeded (ro) */ + + int :32; int :32; int :32; int :32; + int :32; int :32; int :32; int :32; + int :32; int :32; int :32; int :32; +}; + +asmlinkage int sys_old_adjtimex(struct timex32 *txc_p) +{ + struct timex txc; + int ret; + + /* copy relevant bits of struct timex. */ + if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) || + copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) - + offsetof(struct timex32, time))) + return -EFAULT; + + if ((ret = do_adjtimex(&txc))) + return ret; + + /* copy back to timex32 */ + if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) || + (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) - + offsetof(struct timex32, tick))) || + (put_tv32(&txc_p->time, &txc.time))) + return -EFAULT; + + return 0; } 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 Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/process.c Wed Mar 18 05:56:44 1998 @@ -39,6 +39,7 @@ #include #include #include +#include /* * Initial task structure. Make this a per-architecture thing, @@ -50,6 +51,7 @@ unsigned long init_user_stack[1024] = { STACK_MAGIC, }; static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; +static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; @@ -198,6 +200,10 @@ void flush_thread(void) { + /* Arrange for each exec'ed process to start off with a + clean slate wrt the fpu. */ + current->tss.flags &= ~IEEE_SW_MASK; + wrfpcr(FPCR_DYN_NORMAL); } void release_thread(struct task_struct *dead_task) diff -ur --new-file old/linux/arch/alpha/kernel/pyxis.c new/linux/arch/alpha/kernel/pyxis.c --- old/linux/arch/alpha/kernel/pyxis.c Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/pyxis.c Thu Feb 26 23:43:37 1998 @@ -4,6 +4,7 @@ * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com). * */ +#include /* CONFIG_ALPHA_RUFFIAN. */ #include #include #include @@ -16,6 +17,10 @@ #include #include +/* NOTE: Herein are back-to-back mb insns. They are magic. + A plausible explanation is that the i/o controler does not properly + handle the system transaction. Another involves timing. Ho hum. */ + extern struct hwrpb_struct *hwrpb; extern asmlinkage void wrmces(unsigned long mces); extern int alpha_sys_type; @@ -153,6 +158,7 @@ /* access configuration space: */ value = *(vuip)addr; mb(); + mb(); /* magic */ if (PYXIS_mcheck_taken) { PYXIS_mcheck_taken = 0; value = 0xffffffffU; @@ -228,6 +234,7 @@ /* access configuration space: */ *(vuip)addr = value; mb(); + mb(); /* magic */ PYXIS_mcheck_expected = 0; mb(); @@ -369,6 +376,10 @@ mb() ; pyxis_err = *(vuip)PYXIS_ERR ; +#ifdef CONFIG_ALPHA_RUFFIAN + printk("pyxis_init: Skipping window register rewrites --" + " trust DeskStation firmware!\n"); +#else /* * Set up the PCI->physical memory translation windows. * For now, windows 1,2 and 3 are disabled. In the future, we may @@ -384,6 +395,7 @@ *(vuip)PYXIS_W2_BASE = 0x0 ; *(vuip)PYXIS_W3_BASE = 0x0 ; mb(); +#endif /* * check ASN in HWRPB for validity, report if bad @@ -473,11 +485,13 @@ * ignore the machine check. */ mb(); + mb(); /* magic */ if (PYXIS_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) { DBG(("PYXIS machine check expected\n")); PYXIS_mcheck_expected = 0; PYXIS_mcheck_taken = 1; mb(); + mb(); /* magic */ draina(); pyxis_pci_clr_err(); wrmces(0x7); @@ -494,6 +508,7 @@ PYXIS_mcheck_expected = 0; PYXIS_mcheck_taken = 1; mb(); + mb(); /* magic */ draina(); pyxis_pci_clr_err(); wrmces(0x7); @@ -501,3 +516,42 @@ } #endif } + +#if defined(CONFIG_ALPHA_RUFFIAN) +/* Note: This is only used by MILO, AFAIK... */ +/* + * The DeskStation Ruffian motherboard firmware does not place + * the memory size in the PALimpure area. Therefore, we use + * the Bank Configuration Registers in PYXIS to obtain the size. + */ +unsigned long pyxis_get_bank_size(unsigned long offset) +{ + unsigned long bank_addr, bank, ret = 0; + + /* Valid offsets are: 0x800, 0x840 and 0x880 + since Ruffian only uses three banks. */ + bank_addr = (unsigned long)PYXIS_MCR + offset; + bank = *(vulp)bank_addr; + + /* Check BANK_ENABLE */ + if (bank & 0x01) { + static unsigned long size[] = { + 0x40000000UL, /* 0x00, 1G */ + 0x20000000UL, /* 0x02, 512M */ + 0x10000000UL, /* 0x04, 256M */ + 0x08000000UL, /* 0x06, 128M */ + 0x04000000UL, /* 0x08, 64M */ + 0x02000000UL, /* 0x0a, 32M */ + 0x01000000UL, /* 0x0c, 16M */ + 0x00800000UL, /* 0x0e, 8M */ + 0x80000000UL, /* 0x10, 2G */ + }; + + bank = (bank & 0x1e) >> 1; + if (bank < sizeof(size)/sizeof(*size)) + ret = size[bank]; + } + + return ret; +} +#endif /* CONFIG_ALPHA_RUFFIAN */ 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 Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/setup.c Mon Feb 23 19:25:10 1998 @@ -107,11 +107,13 @@ outb(LATCH >> 8, 0x40); /* MSB */ request_region(0x40, 0x20, "timer"); /* reserve pit */ #else +#ifndef CONFIG_ALPHA_RUFFIAN outb(0x36, 0x43); /* counter 0: system timer */ outb(0x00, 0x40); outb(0x00, 0x40); - request_region(0x70, 0x10, "timer"); /* reserve rtc */ #endif + request_region(0x70, 0x10, "timer"); /* reserve rtc */ +#endif /* RTC */ outb(0xb6, 0x43); /* counter 2: speaker */ outb(0x31, 0x42); @@ -186,38 +188,115 @@ #endif } + +#define N(a) (sizeof(a)/sizeof(a[0])) + + +static void +get_sysnames(long type, long variation, + char **type_name, char **variation_name) +{ + static char *sys_unknown = "Unknown"; + static char *systype_names[] = { + "0", + "ADU", "Cobra", "Ruby", "Flamingo", "Mannequin", "Jensen", + "Pelican", "Morgan", "Sable", "Medulla", "Noname", + "Turbolaser", "Avanti", "Mustang", "Alcor", "Tradewind", + "Mikasa", "EB64", "EB66", "EB64+", "AlphaBook1", + "Rawhide", "K2", "Lynx", "XL", "EB164", "Noritake", + "Cortex", "29", "Miata", "XXM", "Takara", "Yukon", + "Tsunami", "Wildfire", "CUSCO" + }; + + static char *unofficial_names[] = {"100", "Ruffian"}; + + static char * eb164_names[] = {"EB164", "PC164", "LX164", "SX164"}; + static int eb164_indices[] = {0,0,0,1,1,1,1,1,2,2,2,2,3,3,3,3}; + + static char * alcor_names[] = {"Alcor", "Maverick", "Bret"}; + static int alcor_indices[] = {0,0,0,1,1,1,0,0,0,0,0,0,2,2,2,2,2,2}; + + static char * eb64p_names[] = {"EB64+", "Cabriolet", "AlphaPCI64"}; + static int eb64p_indices[] = {0,0,1.2}; + + static char * eb66_names[] = {"EB66", "EB66+"}; + static int eb66_indices[] = {0,0,1}; + + long member; + + /* Restore real CABRIO and EB66+ family names, ie EB64+ and EB66 */ + if (type < 0) + type = -type; + + /* If not in the tables, make it UNKNOWN, + else set type name to family */ + if (type < N(systype_names)) { + *type_name = systype_names[type]; + } else if ((type > ST_UNOFFICIAL_BIAS) && + (type - ST_UNOFFICIAL_BIAS) < N(unofficial_names)) { + *type_name = unofficial_names[type - ST_UNOFFICIAL_BIAS]; + } else { + *type_name = sys_unknown; + *variation_name = sys_unknown; + return; + } + + /* Set variation to "0"; if variation is zero, done */ + *variation_name = systype_names[0]; + if (variation == 0) { + return; + } + + member = (variation >> 10) & 0x3f; /* member ID is a bit-field */ + + switch (type) { + case ST_DEC_EB164: + if (member < N(eb164_indices)) + *variation_name = eb164_names[eb164_indices[member]]; + break; + case ST_DEC_ALCOR: + if (member < N(alcor_indices)) + *variation_name = alcor_names[alcor_indices[member]]; + break; + case ST_DEC_EB64P: + if (member < N(eb64p_indices)) + *variation_name = eb64p_names[eb64p_indices[member]]; + break; + case ST_DEC_EB66: + if (member < N(eb66_indices)) + *variation_name = eb66_names[eb66_indices[member]]; + break; + } +} + /* * BUFFER is PAGE_SIZE bytes long. */ int get_cpuinfo(char *buffer) { - const char *cpu_name[] = { - "EV3", "EV4", "Unknown 1", "LCA4", "EV5", "EV45", "EV56", - "EV6", "PCA56" + static char *cpu_names[] = { + "EV3", "EV4", "Unknown", "LCA4", "EV5", "EV45", "EV56", + "EV6", "PCA56", "PCA57" }; -# define SYSTYPE_NAME_BIAS 20 - const char *systype_name[] = { - "Cabriolet", "EB66P", "-18", "-17", "-16", "-15", - "-14", "-13", "-12", "-11", "-10", "-9", "-8", - "-7", "-6", "-5", "-4", "-3", "-2", "-1", "0", - "ADU", "Cobra", "Ruby", "Flamingo", "5", "Jensen", - "Pelican", "8", "Sable", "AXPvme", "Noname", - "Turbolaser", "Avanti", "Mustang", "Alcor", "16", - "Mikasa", "18", "EB66", "EB64+", "AlphaBook1", - "Rawhide", "Lego", "Lynx", "25", "EB164", "Noritake", - "Cortex", "29", "Miata", "31", "Takara", "Yukon" - }; - struct percpu_struct *cpu; - unsigned int cpu_index; - long sysname_index; + extern struct unaligned_stat { unsigned long count, va, pc; } unaligned[2]; -# define N(a) (sizeof(a)/sizeof(a[0])) + + struct percpu_struct *cpu; + unsigned int cpu_index; + char *cpu_name; + char *systype_name; + char *sysvariation_name; cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); cpu_index = (unsigned) (cpu->type - 1); - sysname_index = hwrpb->sys_type + SYSTYPE_NAME_BIAS; + cpu_name = "Unknown"; + if (cpu_index < N(cpu_names)) + cpu_name = cpu_names[cpu_index]; + + get_sysnames(hwrpb->sys_type, hwrpb->sys_variation, + &systype_name, &sysvariation_name); return sprintf(buffer, "cpu\t\t\t: Alpha\n" @@ -226,7 +305,7 @@ "cpu revision\t\t: %ld\n" "cpu serial number\t: %s\n" "system type\t\t: %s\n" - "system variation\t: %ld\n" + "system variation\t: %s\n" "system revision\t\t: %ld\n" "system serial number\t: %s\n" "cycle frequency [Hz]\t: %lu\n" @@ -238,12 +317,9 @@ "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n", - (cpu_index < N(cpu_name) - ? cpu_name[cpu_index] : "Unknown"), - cpu->variation, cpu->revision, (char*)cpu->serial_no, - (sysname_index < N(systype_name) - ? systype_name[sysname_index] : "Unknown"), - hwrpb->sys_variation, hwrpb->sys_revision, + cpu_name, cpu->variation, cpu->revision, + (char*)cpu->serial_no, + systype_name, sysvariation_name, hwrpb->sys_revision, (char*)hwrpb->ssn, hwrpb->cycle_freq, hwrpb->intr_freq / 4096, @@ -254,5 +330,4 @@ loops_per_sec / 500000, (loops_per_sec / 5000) % 100, unaligned[0].count, unaligned[0].pc, unaligned[0].va, unaligned[1].count, unaligned[1].pc, unaligned[1].va); -# undef N } diff -ur --new-file old/linux/arch/alpha/kernel/signal.c new/linux/arch/alpha/kernel/signal.c --- old/linux/arch/alpha/kernel/signal.c Tue Dec 9 18:31:18 1997 +++ new/linux/arch/alpha/kernel/signal.c Sun Jan 25 19:35:16 1998 @@ -116,7 +116,7 @@ asmlinkage int sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact, - void *restorer, size_t sigsetsize) + size_t sigsetsize, void *restorer) { struct k_sigaction new_ka, old_ka; int ret; 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 Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/kernel/smc37c669.c Thu Feb 26 23:43:37 1998 @@ -0,0 +1,2583 @@ +/* + * SMC 37C669 initialization code + */ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +#define SMC_DEBUG 0 + +/* File: smcc669_def.h + * + * Copyright (C) 1997 by + * Digital Equipment Corporation, Maynard, Massachusetts. + * All rights reserved. + * + * This software is furnished under a license and may be used and copied + * only in accordance of the terms of such license and with the + * inclusion of the above copyright notice. This software or any other + * copies thereof may not be provided or otherwise made available to any + * other person. No title to and ownership of the software is hereby + * transferred. + * + * The information in this software is subject to change without notice + * and should not be construed as a commitment by Digital Equipment + * Corporation. + * + * Digital assumes no responsibility for the use or reliability of its + * software on equipment which is not supplied by Digital. + * + * + * Abstract: + * + * This file contains header definitions for the SMC37c669 + * Super I/O controller. + * + * Author: + * + * Eric Rasmussen + * + * Modification History: + * + * er 28-Jan-1997 Initial Entry + */ + +#ifndef __SMC37c669_H +#define __SMC37c669_H + +/* +** Macros for handling device IRQs +** +** The mask acts as a flag used in mapping actual ISA IRQs (0 - 15) +** to device IRQs (A - H). +*/ +#define SMC37c669_DEVICE_IRQ_MASK 0x80000000 +#define SMC37c669_DEVICE_IRQ( __i ) \ + ((SMC37c669_DEVICE_IRQ_MASK) | (__i)) +#define SMC37c669_IS_DEVICE_IRQ(__i) \ + (((__i) & (SMC37c669_DEVICE_IRQ_MASK)) == (SMC37c669_DEVICE_IRQ_MASK)) +#define SMC37c669_RAW_DEVICE_IRQ(__i) \ + ((__i) & ~(SMC37c669_DEVICE_IRQ_MASK)) + +/* +** Macros for handling device DRQs +** +** The mask acts as a flag used in mapping actual ISA DMA +** channels to device DMA channels (A - C). +*/ +#define SMC37c669_DEVICE_DRQ_MASK 0x80000000 +#define SMC37c669_DEVICE_DRQ(__d) \ + ((SMC37c669_DEVICE_DRQ_MASK) | (__d)) +#define SMC37c669_IS_DEVICE_DRQ(__d) \ + (((__d) & (SMC37c669_DEVICE_DRQ_MASK)) == (SMC37c669_DEVICE_DRQ_MASK)) +#define SMC37c669_RAW_DEVICE_DRQ(__d) \ + ((__d) & ~(SMC37c669_DEVICE_DRQ_MASK)) + +#define SMC37c669_DEVICE_ID 0x3 + +/* +** SMC37c669 Device Function Definitions +*/ +#define SERIAL_0 0 +#define SERIAL_1 1 +#define PARALLEL_0 2 +#define FLOPPY_0 3 +#define IDE_0 4 +#define NUM_FUNCS 5 + +/* +** Default Device Function Mappings +*/ +#define COM1_BASE 0x3F8 +#define COM1_IRQ 4 +#define COM2_BASE 0x2F8 +#define COM2_IRQ 3 +#define PARP_BASE 0x3BC +#define PARP_IRQ 7 +#define PARP_DRQ 3 +#define FDC_BASE 0x3F0 +#define FDC_IRQ 6 +#define FDC_DRQ 2 + +/* +** Configuration On/Off Key Definitions +*/ +#define SMC37c669_CONFIG_ON_KEY 0x55 +#define SMC37c669_CONFIG_OFF_KEY 0xAA + +/* +** SMC 37c669 Device IRQs +*/ +#define SMC37c669_DEVICE_IRQ_A ( SMC37c669_DEVICE_IRQ( 0x01 ) ) +#define SMC37c669_DEVICE_IRQ_B ( SMC37c669_DEVICE_IRQ( 0x02 ) ) +#define SMC37c669_DEVICE_IRQ_C ( SMC37c669_DEVICE_IRQ( 0x03 ) ) +#define SMC37c669_DEVICE_IRQ_D ( SMC37c669_DEVICE_IRQ( 0x04 ) ) +#define SMC37c669_DEVICE_IRQ_E ( SMC37c669_DEVICE_IRQ( 0x05 ) ) +#define SMC37c669_DEVICE_IRQ_F ( SMC37c669_DEVICE_IRQ( 0x06 ) ) +/* SMC37c669_DEVICE_IRQ_G *** RESERVED ***/ +#define SMC37c669_DEVICE_IRQ_H ( SMC37c669_DEVICE_IRQ( 0x08 ) ) + +/* +** SMC 37c669 Device DMA Channel Definitions +*/ +#define SMC37c669_DEVICE_DRQ_A ( SMC37c669_DEVICE_DRQ( 0x01 ) ) +#define SMC37c669_DEVICE_DRQ_B ( SMC37c669_DEVICE_DRQ( 0x02 ) ) +#define SMC37c669_DEVICE_DRQ_C ( SMC37c669_DEVICE_DRQ( 0x03 ) ) + +/* +** Configuration Register Index Definitions +*/ +#define SMC37c669_CR00_INDEX 0x00 +#define SMC37c669_CR01_INDEX 0x01 +#define SMC37c669_CR02_INDEX 0x02 +#define SMC37c669_CR03_INDEX 0x03 +#define SMC37c669_CR04_INDEX 0x04 +#define SMC37c669_CR05_INDEX 0x05 +#define SMC37c669_CR06_INDEX 0x06 +#define SMC37c669_CR07_INDEX 0x07 +#define SMC37c669_CR08_INDEX 0x08 +#define SMC37c669_CR09_INDEX 0x09 +#define SMC37c669_CR0A_INDEX 0x0A +#define SMC37c669_CR0B_INDEX 0x0B +#define SMC37c669_CR0C_INDEX 0x0C +#define SMC37c669_CR0D_INDEX 0x0D +#define SMC37c669_CR0E_INDEX 0x0E +#define SMC37c669_CR0F_INDEX 0x0F +#define SMC37c669_CR10_INDEX 0x10 +#define SMC37c669_CR11_INDEX 0x11 +#define SMC37c669_CR12_INDEX 0x12 +#define SMC37c669_CR13_INDEX 0x13 +#define SMC37c669_CR14_INDEX 0x14 +#define SMC37c669_CR15_INDEX 0x15 +#define SMC37c669_CR16_INDEX 0x16 +#define SMC37c669_CR17_INDEX 0x17 +#define SMC37c669_CR18_INDEX 0x18 +#define SMC37c669_CR19_INDEX 0x19 +#define SMC37c669_CR1A_INDEX 0x1A +#define SMC37c669_CR1B_INDEX 0x1B +#define SMC37c669_CR1C_INDEX 0x1C +#define SMC37c669_CR1D_INDEX 0x1D +#define SMC37c669_CR1E_INDEX 0x1E +#define SMC37c669_CR1F_INDEX 0x1F +#define SMC37c669_CR20_INDEX 0x20 +#define SMC37c669_CR21_INDEX 0x21 +#define SMC37c669_CR22_INDEX 0x22 +#define SMC37c669_CR23_INDEX 0x23 +#define SMC37c669_CR24_INDEX 0x24 +#define SMC37c669_CR25_INDEX 0x25 +#define SMC37c669_CR26_INDEX 0x26 +#define SMC37c669_CR27_INDEX 0x27 +#define SMC37c669_CR28_INDEX 0x28 +#define SMC37c669_CR29_INDEX 0x29 + +/* +** Configuration Register Alias Definitions +*/ +#define SMC37c669_DEVICE_ID_INDEX SMC37c669_CR0D_INDEX +#define SMC37c669_DEVICE_REVISION_INDEX SMC37c669_CR0E_INDEX +#define SMC37c669_FDC_BASE_ADDRESS_INDEX SMC37c669_CR20_INDEX +#define SMC37c669_IDE_BASE_ADDRESS_INDEX SMC37c669_CR21_INDEX +#define SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX SMC37c669_CR22_INDEX +#define SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX SMC37c669_CR23_INDEX +#define SMC37c669_SERIAL0_BASE_ADDRESS_INDEX SMC37c669_CR24_INDEX +#define SMC37c669_SERIAL1_BASE_ADDRESS_INDEX SMC37c669_CR25_INDEX +#define SMC37c669_PARALLEL_FDC_DRQ_INDEX SMC37c669_CR26_INDEX +#define SMC37c669_PARALLEL_FDC_IRQ_INDEX SMC37c669_CR27_INDEX +#define SMC37c669_SERIAL_IRQ_INDEX SMC37c669_CR28_INDEX + +/* +** Configuration Register Definitions +** +** The INDEX (write only) and DATA (read/write) ports are effective +** only when the chip is in the Configuration State. +*/ +typedef struct _SMC37c669_CONFIG_REGS { + unsigned char index_port; + unsigned char data_port; +} SMC37c669_CONFIG_REGS; + +/* +** CR00 - default value 0x28 +** +** IDE_EN (CR00<1:0>): +** 0x - 30ua pull-ups on nIDEEN, nHDCS0, NHDCS1 +** 11 - IRQ_H available as IRQ output, +** IRRX2, IRTX2 available as alternate IR pins +** 10 - nIDEEN, nHDCS0, nHDCS1 used to control IDE +** +** VALID (CR00<7>): +** A high level on this software controlled bit can +** be used to indicate that a valid configuration +** cycle has occurred. The control software must +** take care to set this bit at the appropriate times. +** Set to zero after power up. This bit has no +** effect on any other hardware in the chip. +** +*/ +typedef union _SMC37c669_CR00 { + unsigned char as_uchar; + struct { + unsigned ide_en : 2; /* See note above */ + unsigned reserved1 : 1; /* RAZ */ + unsigned fdc_pwr : 1; /* 1 = supply power to FDC */ + unsigned reserved2 : 3; /* Read as 010b */ + unsigned valid : 1; /* See note above */ + } by_field; +} SMC37c669_CR00; + +/* +** CR01 - default value 0x9C +*/ +typedef union _SMC37c669_CR01 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 2; /* RAZ */ + unsigned ppt_pwr : 1; /* 1 = supply power to PPT */ + unsigned ppt_mode : 1; /* 1 = Printer mode, 0 = EPP */ + unsigned reserved2 : 1; /* Read as 1 */ + unsigned reserved3 : 2; /* RAZ */ + unsigned lock_crx: 1; /* Lock CR00 - CR18 */ + } by_field; +} SMC37c669_CR01; + +/* +** CR02 - default value 0x88 +*/ +typedef union _SMC37c669_CR02 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 3; /* RAZ */ + unsigned uart1_pwr : 1; /* 1 = supply power to UART1 */ + unsigned reserved2 : 3; /* RAZ */ + unsigned uart2_pwr : 1; /* 1 = supply power to UART2 */ + } by_field; +} SMC37c669_CR02; + +/* +** CR03 - default value 0x78 +** +** CR03<7> CR03<2> Pin 94 +** ------- ------- ------ +** 0 X DRV2 (input) +** 1 0 ADRX +** 1 1 IRQ_B +** +** CR03<6> CR03<5> Op Mode +** ------- ------- ------- +** 0 0 Model 30 +** 0 1 PS/2 +** 1 0 Reserved +** 1 1 AT Mode +*/ +typedef union _SMC37c669_CR03 { + unsigned char as_uchar; + struct { + unsigned pwrgd_gamecs : 1; /* 1 = PWRGD, 0 = GAMECS */ + unsigned fdc_mode2 : 1; /* 1 = Enhanced Mode 2 */ + unsigned pin94_0 : 1; /* See note above */ + unsigned reserved1 : 1; /* RAZ */ + unsigned drvden : 1; /* 1 = high, 0 - output */ + unsigned op_mode : 2; /* See note above */ + unsigned pin94_1 : 1; /* See note above */ + } by_field; +} SMC37c669_CR03; + +/* +** CR04 - default value 0x00 +** +** PP_EXT_MODE: +** If CR01 = 0 and PP_EXT_MODE = +** 00 - Standard and Bidirectional +** 01 - EPP mode and SPP +** 10 - ECP mode +** In this mode, 2 drives can be supported +** directly, 3 or 4 drives must use external +** 4 drive support. SPP can be selected +** through the ECR register of ECP as mode 000. +** 11 - ECP mode and EPP mode +** In this mode, 2 drives can be supported +** directly, 3 or 4 drives must use external +** 4 drive support. SPP can be selected +** through the ECR register of ECP as mode 000. +** In this mode, EPP can be selected through +** the ECR register of ECP as mode 100. +** +** PP_FDC: +** 00 - Normal +** 01 - PPFD1 +** 10 - PPFD2 +** 11 - Reserved +** +** MIDI1: +** Serial Clock Select: +** A low level on this bit disables MIDI support, +** clock = divide by 13. A high level on this +** bit enables MIDI support, clock = divide by 12. +** +** MIDI operates at 31.25 Kbps which can be derived +** from 125 KHz (24 MHz / 12 = 2 MHz, 2 MHz / 16 = 125 KHz) +** +** ALT_IO: +** 0 - Use pins IRRX, IRTX +** 1 - Use pins IRRX2, IRTX2 +** +** If this bit is set, the IR receive and transmit +** functions will not be available on pins 25 and 26 +** unless CR00 = 11. +*/ +typedef union _SMC37c669_CR04 { + unsigned char as_uchar; + struct { + unsigned ppt_ext_mode : 2; /* See note above */ + unsigned ppt_fdc : 2; /* See note above */ + unsigned midi1 : 1; /* See note above */ + unsigned midi2 : 1; /* See note above */ + unsigned epp_type : 1; /* 0 = EPP 1.9, 1 = EPP 1.7 */ + unsigned alt_io : 1; /* See note above */ + } by_field; +} SMC37c669_CR04; + +/* +** CR05 - default value 0x00 +** +** DEN_SEL: +** 00 - Densel output normal +** 01 - Reserved +** 10 - Densel output 1 +** 11 - Densel output 0 +** +*/ +typedef union _SMC37c669_CR05 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 2; /* RAZ */ + unsigned fdc_dma_mode : 1; /* 0 = burst, 1 = non-burst */ + unsigned den_sel : 2; /* See note above */ + unsigned swap_drv : 1; /* Swap the FDC motor selects */ + unsigned extx4 : 1; /* 0 = 2 drive, 1 = external 4 drive decode */ + unsigned reserved2 : 1; /* RAZ */ + } by_field; +} SMC37c669_CR05; + +/* +** CR06 - default value 0xFF +*/ +typedef union _SMC37c669_CR06 { + unsigned char as_uchar; + struct { + unsigned floppy_a : 2; /* Type of floppy drive A */ + unsigned floppy_b : 2; /* Type of floppy drive B */ + unsigned floppy_c : 2; /* Type of floppy drive C */ + unsigned floppy_d : 2; /* Type of floppy drive D */ + } by_field; +} SMC37c669_CR06; + +/* +** CR07 - default value 0x00 +** +** Auto Power Management CR07<7:4>: +** 0 - Auto Powerdown disabled (default) +** 1 - Auto Powerdown enabled +** +** This bit is reset to the default state by POR or +** a hardware reset. +** +*/ +typedef union _SMC37c669_CR07 { + unsigned char as_uchar; + struct { + unsigned floppy_boot : 2; /* 0 = A:, 1 = B: */ + unsigned reserved1 : 2; /* RAZ */ + unsigned ppt_en : 1; /* See note above */ + unsigned uart1_en : 1; /* See note above */ + unsigned uart2_en : 1; /* See note above */ + unsigned fdc_en : 1; /* See note above */ + } by_field; +} SMC37c669_CR07; + +/* +** CR08 - default value 0x00 +*/ +typedef union _SMC37c669_CR08 { + unsigned char as_uchar; + struct { + unsigned zero : 4; /* 0 */ + unsigned addrx7_4 : 4; /* ADR<7:3> for ADRx decode */ + } by_field; +} SMC37c669_CR08; + +/* +** CR09 - default value 0x00 +** +** ADRx_CONFIG: +** 00 - ADRx disabled +** 01 - 1 byte decode A<3:0> = 0000b +** 10 - 8 byte block decode A<3:0> = 0XXXb +** 11 - 16 byte block decode A<3:0> = XXXXb +** +*/ +typedef union _SMC37c669_CR09 { + unsigned char as_uchar; + struct { + unsigned adra8 : 3; /* ADR<10:8> for ADRx decode */ + unsigned reserved1 : 3; + unsigned adrx_config : 2; /* See note above */ + } by_field; +} SMC37c669_CR09; + +/* +** CR0A - default value 0x00 +*/ +typedef union _SMC37c669_CR0A { + unsigned char as_uchar; + struct { + unsigned ecp_fifo_threshold : 4; + unsigned reserved1 : 4; + } by_field; +} SMC37c669_CR0A; + +/* +** CR0B - default value 0x00 +*/ +typedef union _SMC37c669_CR0B { + unsigned char as_uchar; + struct { + unsigned fdd0_drtx : 2; /* FDD0 Data Rate Table */ + unsigned fdd1_drtx : 2; /* FDD1 Data Rate Table */ + unsigned fdd2_drtx : 2; /* FDD2 Data Rate Table */ + unsigned fdd3_drtx : 2; /* FDD3 Data Rate Table */ + } by_field; +} SMC37c669_CR0B; + +/* +** CR0C - default value 0x00 +** +** UART2_MODE: +** 000 - Standard (default) +** 001 - IrDA (HPSIR) +** 010 - Amplitude Shift Keyed IR @500 KHz +** 011 - Reserved +** 1xx - Reserved +** +*/ +typedef union _SMC37c669_CR0C { + unsigned char as_uchar; + struct { + unsigned uart2_rcv_polarity : 1; /* 1 = invert RX */ + unsigned uart2_xmit_polarity : 1; /* 1 = invert TX */ + unsigned uart2_duplex : 1; /* 1 = full, 0 = half */ + unsigned uart2_mode : 3; /* See note above */ + unsigned uart1_speed : 1; /* 1 = high speed enabled */ + unsigned uart2_speed : 1; /* 1 = high speed enabled */ + } by_field; +} SMC37c669_CR0C; + +/* +** CR0D - default value 0x03 +** +** Device ID Register - read only +*/ +typedef union _SMC37c669_CR0D { + unsigned char as_uchar; + struct { + unsigned device_id : 8; /* Returns 0x3 in this field */ + } by_field; +} SMC37c669_CR0D; + +/* +** CR0E - default value 0x02 +** +** Device Revision Register - read only +*/ +typedef union _SMC37c669_CR0E { + unsigned char as_uchar; + struct { + unsigned device_rev : 8; /* Returns 0x2 in this field */ + } by_field; +} SMC37c669_CR0E; + +/* +** CR0F - default value 0x00 +*/ +typedef union _SMC37c669_CR0F { + unsigned char as_uchar; + struct { + unsigned test0 : 1; /* Reserved - set to 0 */ + unsigned test1 : 1; /* Reserved - set to 0 */ + unsigned test2 : 1; /* Reserved - set to 0 */ + unsigned test3 : 1; /* Reserved - set t0 0 */ + unsigned test4 : 1; /* Reserved - set to 0 */ + unsigned test5 : 1; /* Reserved - set t0 0 */ + unsigned test6 : 1; /* Reserved - set t0 0 */ + unsigned test7 : 1; /* Reserved - set to 0 */ + } by_field; +} SMC37c669_CR0F; + +/* +** CR10 - default value 0x00 +*/ +typedef union _SMC37c669_CR10 { + unsigned char as_uchar; + struct { + unsigned reserved1 : 3; /* RAZ */ + unsigned pll_gain : 1; /* 1 = 3V, 2 = 5V operation */ + unsigned pll_stop : 1; /* 1 = stop PLLs */ + unsigned ace_stop : 1; /* 1 = stop UART clocks */ + unsigned pll_clock_ctrl : 1; /* 0 = 14.318 MHz, 1 = 24 MHz */ + unsigned ir_test : 1; /* Enable IR test mode */ + } by_field; +} SMC37c669_CR10; + +/* +** CR11 - default value 0x00 +*/ +typedef union _SMC37c669_CR11 { + unsigned char as_uchar; + struct { + unsigned ir_loopback : 1; /* Internal IR loop back */ + unsigned test_10ms : 1; /* Test 10ms autopowerdown FDC timeout */ + unsigned reserved1 : 6; /* RAZ */ + } by_field; +} SMC37c669_CR11; + +/* +** CR12 - CR1D are reserved registers +*/ + +/* +** CR1E - default value 0x80 +** +** GAMECS: +** 00 - GAMECS disabled +** 01 - 1 byte decode ADR<3:0> = 0001b +** 10 - 8 byte block decode ADR<3:0> = 0XXXb +** 11 - 16 byte block decode ADR<3:0> = XXXXb +** +*/ +typedef union _SMC37c66_CR1E { + unsigned char as_uchar; + struct { + unsigned gamecs_config: 2; /* See note above */ + unsigned gamecs_addr9_4 : 6; /* GAMECS Addr<9:4> */ + } by_field; +} SMC37c669_CR1E; + +/* +** CR1F - default value 0x00 +** +** DT0 DT1 DRVDEN0 DRVDEN1 Drive Type +** --- --- ------- ------- ---------- +** 0 0 DENSEL DRATE0 4/2/1 MB 3.5" +** 2/1 MB 5.25" +** 2/1.6/1 MB 3.5" (3-mode) +** 0 1 DRATE1 DRATE0 +** 1 0 nDENSEL DRATE0 PS/2 +** 1 1 DRATE0 DRATE1 +** +** Note: DENSEL, DRATE1, and DRATE0 map onto two output +** pins - DRVDEN0 and DRVDEN1. +** +*/ +typedef union _SMC37c669_CR1F { + unsigned char as_uchar; + struct { + unsigned fdd0_drive_type : 2; /* FDD0 drive type */ + unsigned fdd1_drive_type : 2; /* FDD1 drive type */ + unsigned fdd2_drive_type : 2; /* FDD2 drive type */ + unsigned fdd3_drive_type : 2; /* FDD3 drive type */ + } by_field; +} SMC37c669_CR1F; + +/* +** CR20 - default value 0x3C +** +** FDC Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<3:0> = 0XXXb to access. +** +*/ +typedef union _SMC37c669_CR20 { + unsigned char as_uchar; + struct { + unsigned zero : 2; /* 0 */ + unsigned addr9_4 : 6; /* FDC Addr<9:4> */ + } by_field; +} SMC37c669_CR20; + +/* +** CR21 - default value 0x3C +** +** IDE Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<3:0> = 0XXXb to access. +** +*/ +typedef union _SMC37c669_CR21 { + unsigned char as_uchar; + struct { + unsigned zero : 2; /* 0 */ + unsigned addr9_4 : 6; /* IDE Addr<9:4> */ + } by_field; +} SMC37c669_CR21; + +/* +** CR22 - default value 0x3D +** +** IDE Alternate Status Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<3:0> = 0110b to access. +** +*/ +typedef union _SMC37c669_CR22 { + unsigned char as_uchar; + struct { + unsigned zero : 2; /* 0 */ + unsigned addr9_4 : 6; /* IDE Alt Status Addr<9:4> */ + } by_field; +} SMC37c669_CR22; + +/* +** CR23 - default value 0x00 +** +** Parallel Port Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0 to access. +** - If EPP is enabled, A<2:0> = XXXb to access. +** If EPP is NOT enabled, A<1:0> = XXb to access +** +*/ +typedef union _SMC37c669_CR23 { + unsigned char as_uchar; + struct { + unsigned addr9_2 : 8; /* Parallel Port Addr<9:2> */ + } by_field; +} SMC37c669_CR23; + +/* +** CR24 - default value 0x00 +** +** UART1 Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<2:0> = XXXb to access. +** +*/ +typedef union _SMC37c669_CR24 { + unsigned char as_uchar; + struct { + unsigned zero : 1; /* 0 */ + unsigned addr9_3 : 7; /* UART1 Addr<9:3> */ + } by_field; +} SMC37c669_CR24; + +/* +** CR25 - default value 0x00 +** +** UART2 Base Address Register +** - To disable this decode set Addr<9:8> = 0 +** - A<10> = 0, A<2:0> = XXXb to access. +** +*/ +typedef union _SMC37c669_CR25 { + unsigned char as_uchar; + struct { + unsigned zero : 1; /* 0 */ + unsigned addr9_3 : 7; /* UART2 Addr<9:3> */ + } by_field; +} SMC37c669_CR25; + +/* +** CR26 - default value 0x00 +** +** Parallel Port / FDC DMA Select Register +** +** D3 - D0 DMA +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 DMA_A +** 0010 DMA_B +** 0011 DMA_C +** +*/ +typedef union _SMC37c669_CR26 { + unsigned char as_uchar; + struct { + unsigned ppt_drq : 4; /* See note above */ + unsigned fdc_drq : 4; /* See note above */ + } by_field; +} SMC37c669_CR26; + +/* +** CR27 - default value 0x00 +** +** Parallel Port / FDC IRQ Select Register +** +** D3 - D0 IRQ +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 IRQ_A +** 0010 IRQ_B +** 0011 IRQ_C +** 0100 IRQ_D +** 0101 IRQ_E +** 0110 IRQ_F +** 0111 Reserved +** 1000 IRQ_H +** +** Any unselected IRQ REQ is in tristate +** +*/ +typedef union _SMC37c669_CR27 { + unsigned char as_uchar; + struct { + unsigned ppt_irq : 4; /* See note above */ + unsigned fdc_irq : 4; /* See note above */ + } by_field; +} SMC37c669_CR27; + +/* +** CR28 - default value 0x00 +** +** UART IRQ Select Register +** +** D3 - D0 IRQ +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 IRQ_A +** 0010 IRQ_B +** 0011 IRQ_C +** 0100 IRQ_D +** 0101 IRQ_E +** 0110 IRQ_F +** 0111 Reserved +** 1000 IRQ_H +** 1111 share with UART1 (only for UART2) +** +** Any unselected IRQ REQ is in tristate +** +** To share an IRQ between UART1 and UART2, set +** UART1 to use the desired IRQ and set UART2 to +** 0xF to enable sharing mechanism. +** +*/ +typedef union _SMC37c669_CR28 { + unsigned char as_uchar; + struct { + unsigned uart2_irq : 4; /* See note above */ + unsigned uart1_irq : 4; /* See note above */ + } by_field; +} SMC37c669_CR28; + +/* +** CR29 - default value 0x00 +** +** IRQIN IRQ Select Register +** +** D3 - D0 IRQ +** D7 - D4 Selected +** ------- -------- +** 0000 None +** 0001 IRQ_A +** 0010 IRQ_B +** 0011 IRQ_C +** 0100 IRQ_D +** 0101 IRQ_E +** 0110 IRQ_F +** 0111 Reserved +** 1000 IRQ_H +** +** Any unselected IRQ REQ is in tristate +** +*/ +typedef union _SMC37c669_CR29 { + unsigned char as_uchar; + struct { + unsigned irqin_irq : 4; /* See note above */ + unsigned reserved1 : 4; /* RAZ */ + } by_field; +} SMC37c669_CR29; + +/* +** Aliases of Configuration Register formats (should match +** the set of index aliases). +** +** Note that CR24 and CR25 have the same format and are the +** base address registers for UART1 and UART2. Because of +** this we only define 1 alias here - for CR24 - as the serial +** base address register. +** +** Note that CR21 and CR22 have the same format and are the +** base address and alternate status address registers for +** the IDE controller. Because of this we only define 1 alias +** here - for CR21 - as the IDE address register. +** +*/ +typedef SMC37c669_CR0D SMC37c669_DEVICE_ID_REGISTER; +typedef SMC37c669_CR0E SMC37c669_DEVICE_REVISION_REGISTER; +typedef SMC37c669_CR20 SMC37c669_FDC_BASE_ADDRESS_REGISTER; +typedef SMC37c669_CR21 SMC37c669_IDE_ADDRESS_REGISTER; +typedef SMC37c669_CR23 SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER; +typedef SMC37c669_CR24 SMC37c669_SERIAL_BASE_ADDRESS_REGISTER; +typedef SMC37c669_CR26 SMC37c669_PARALLEL_FDC_DRQ_REGISTER; +typedef SMC37c669_CR27 SMC37c669_PARALLEL_FDC_IRQ_REGISTER; +typedef SMC37c669_CR28 SMC37c669_SERIAL_IRQ_REGISTER; + +/* +** ISA/Device IRQ Translation Table Entry Definition +*/ +typedef struct _SMC37c669_IRQ_TRANSLATION_ENTRY { + int device_irq; + int isa_irq; +} SMC37c669_IRQ_TRANSLATION_ENTRY; + +/* +** ISA/Device DMA Translation Table Entry Definition +*/ +typedef struct _SMC37c669_DRQ_TRANSLATION_ENTRY { + int device_drq; + int isa_drq; +} SMC37c669_DRQ_TRANSLATION_ENTRY; + +/* +** External Interface Function Prototype Declarations +*/ + +SMC37c669_CONFIG_REGS *SMC37c669_detect( + void +); + +unsigned int SMC37c669_enable_device( + unsigned int func +); + +unsigned int SMC37c669_disable_device( + unsigned int func +); + +unsigned int SMC37c669_configure_device( + unsigned int func, + int port, + int irq, + int drq +); + +void SMC37c669_display_device_info( + void +); + +#endif /* __SMC37c669_H */ + +/* file: smcc669.c + * + * Copyright (C) 1997 by + * Digital Equipment Corporation, Maynard, Massachusetts. + * All rights reserved. + * + * This software is furnished under a license and may be used and copied + * only in accordance of the terms of such license and with the + * inclusion of the above copyright notice. This software or any other + * copies thereof may not be provided or otherwise made available to any + * other person. No title to and ownership of the software is hereby + * transferred. + * + * The information in this software is subject to change without notice + * and should not be construed as a commitment by digital equipment + * corporation. + * + * Digital assumes no responsibility for the use or reliability of its + * software on equipment which is not supplied by digital. + */ + +/* + *++ + * FACILITY: + * + * Alpha SRM Console Firmware + * + * MODULE DESCRIPTION: + * + * SMC37c669 Super I/O controller configuration routines. + * + * AUTHORS: + * + * Eric Rasmussen + * + * CREATION DATE: + * + * 28-Jan-1997 + * + * MODIFICATION HISTORY: + * + * er 01-May-1997 Fixed pointer conversion errors in + * SMC37c669_get_device_config(). + * er 28-Jan-1997 Initial version. + * + *-- + */ +#if 0 +/* $INCLUDE_OPTIONS$ */ +#include "cp$inc:platform_io.h" +/* $INCLUDE_OPTIONS_END$ */ +#include "cp$src:common.h" +#include "cp$inc:prototypes.h" +#include "cp$src:kernel_def.h" +#include "cp$src:msg_def.h" +#include "cp$src:smcc669_def.h" +/* Platform-specific includes */ +#include "cp$src:platform.h" +#endif + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define wb( _x_, _y_ ) outb( _y_, (unsigned int)((unsigned long)_x_) ) +#define rb( _x_ ) inb( (unsigned int)((unsigned long)_x_) ) + +/* +** Local storage for device configuration information. +** +** Since the SMC37c669 does not provide an explicit +** mechanism for enabling/disabling individual device +** functions, other than unmapping the device, local +** storage for device configuration information is +** allocated here for use in implementing our own +** function enable/disable scheme. +*/ +static struct DEVICE_CONFIG { + unsigned int port1; + unsigned int port2; + unsigned int irq; + unsigned int drq; +} local_config [NUM_FUNCS]; + +/* +** List of all possible addresses for the Super I/O chip +*/ +static unsigned long SMC37c669_Addresses[] __initdata = + { + 0x3F0UL, /* Primary address */ + 0x370UL, /* Secondary address */ + 0UL /* End of list */ + }; + +/* +** Global Pointer to the Super I/O device +*/ +static SMC37c669_CONFIG_REGS *SMC37c669 __initdata = NULL; + +/* +** IRQ Translation Table +** +** The IRQ translation table is a list of SMC37c669 device +** and standard ISA IRQs. +** +*/ +static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata; + +/* +** The following definition is for the default IRQ +** translation table. +*/ +static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[] +__initdata = + { + { SMC37c669_DEVICE_IRQ_A, -1 }, + { SMC37c669_DEVICE_IRQ_B, -1 }, + { SMC37c669_DEVICE_IRQ_C, 7 }, + { SMC37c669_DEVICE_IRQ_D, 6 }, + { SMC37c669_DEVICE_IRQ_E, 4 }, + { SMC37c669_DEVICE_IRQ_F, 3 }, + { SMC37c669_DEVICE_IRQ_H, -1 }, + { -1, -1 } /* End of table */ + }; + +/* +** DRQ Translation Table +** +** The DRQ translation table is a list of SMC37c669 device and +** ISA DMA channels. +** +*/ +static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata; + +/* +** The following definition is the default DRQ +** translation table. +*/ +static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[] +__initdata = + { + { SMC37c669_DEVICE_DRQ_A, 2 }, + { SMC37c669_DEVICE_DRQ_B, 3 }, + { SMC37c669_DEVICE_DRQ_C, -1 }, + { -1, -1 } /* End of table */ + }; + +/* +** Local Function Prototype Declarations +*/ + +static unsigned int SMC37c669_is_device_enabled( + unsigned int func +); + +#if 0 +static unsigned int SMC37c669_get_device_config( + unsigned int func, + int *port, + int *irq, + int *drq +); +#endif + +static void SMC37c669_config_mode( + unsigned int enable +); + +static unsigned char SMC37c669_read_config( + unsigned char index +); + +static void SMC37c669_write_config( + unsigned char index, + unsigned char data +); + +static void SMC37c669_init_local_config( void ); + +static struct DEVICE_CONFIG *SMC37c669_get_config( + unsigned int func +); + +static int SMC37c669_xlate_irq( + unsigned int irq +); + +static int SMC37c669_xlate_drq( + unsigned int drq +); + +#if 0 +/* +** External Data Declarations +*/ + +extern struct LOCK spl_atomic; + +/* +** External Function Prototype Declarations +*/ + +/* From kernel_alpha.mar */ +extern spinlock( + struct LOCK *spl +); + +extern spinunlock( + struct LOCK *spl +); + +/* From filesys.c */ +int allocinode( + char *name, + int can_create, + struct INODE **ipp +); + +extern int null_procedure( void ); + +int smcc669_init( void ); +int smcc669_open( struct FILE *fp, char *info, char *next, char *mode ); +int smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf ); +int smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf ); +int smcc669_close( struct FILE *fp ); + +struct DDB smc_ddb = { + "smc", /* how this routine wants to be called */ + smcc669_read, /* read routine */ + smcc669_write, /* write routine */ + smcc669_open, /* open routine */ + smcc669_close, /* close routine */ + null_procedure, /* name expansion routine */ + null_procedure, /* delete routine */ + null_procedure, /* create routine */ + null_procedure, /* setmode */ + null_procedure, /* validation routine */ + 0, /* class specific use */ + 1, /* allows information */ + 0, /* must be stacked */ + 0, /* is a flash update driver */ + 0, /* is a block device */ + 0, /* not seekable */ + 0, /* is an ethernet device */ + 0, /* is a filesystem driver */ +}; +#endif + +#define spinlock(x) +#define spinunlock(x) + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function detects the presence of an SMC37c669 Super I/O +** controller. +** +** FORMAL PARAMETERS: +** +** None +** +** RETURN VALUE: +** +** Returns a pointer to the device if found, otherwise, +** the NULL pointer is returned. +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +SMC37c669_CONFIG_REGS * __init SMC37c669_detect( void ) +{ + int i; + SMC37c669_DEVICE_ID_REGISTER id; + + for ( i = 0; SMC37c669_Addresses[i] != 0; i++ ) { +/* +** Initialize the device pointer even though we don't yet know if +** the controller is at this address. The support functions access +** the controller through this device pointer so we need to set it +** even when we are looking ... +*/ + SMC37c669 = ( SMC37c669_CONFIG_REGS * )SMC37c669_Addresses[i]; +/* +** Enter configuration mode +*/ + SMC37c669_config_mode( TRUE ); +/* +** Read the device id +*/ + id.as_uchar = SMC37c669_read_config( SMC37c669_DEVICE_ID_INDEX ); +/* +** Exit configuration mode +*/ + SMC37c669_config_mode( FALSE ); +/* +** Does the device id match? If so, assume we have found an +** SMC37c669 controller at this address. +*/ + if ( id.by_field.device_id == SMC37c669_DEVICE_ID ) { +/* +** Initialize the IRQ and DRQ translation tables. +*/ + SMC37c669_irq_table = SMC37c669_default_irq_table; + SMC37c669_drq_table = SMC37c669_default_drq_table; +/* +** erfix +** +** If the platform can't use the IRQ and DRQ defaults set up in this +** file, it should call a platform-specific external routine at this +** point to reset the IRQ and DRQ translation table pointers to point +** at the appropriate tables for the platform. If the defaults are +** acceptable, then the external routine should do nothing. +*/ + +/* +** Put the chip back into configuration mode +*/ + SMC37c669_config_mode( TRUE ); +/* +** Initialize local storage for configuration information +*/ + SMC37c669_init_local_config( ); +/* +** Exit configuration mode +*/ + SMC37c669_config_mode( FALSE ); +/* +** SMC37c669 controller found, break out of search loop +*/ + break; + } + else { +/* +** Otherwise, we did not find an SMC37c669 controller at this +** address so set the device pointer to NULL. +*/ + SMC37c669 = NULL; + } + } + return SMC37c669; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function enables an SMC37c669 device function. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function to enable +** +** RETURN VALUE: +** +** Returns TRUE is the device function was enabled, otherwise, FALSE +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** Enabling a device function in the SMC37c669 controller involves +** setting all of its mappings (port, irq, drq ...). A local +** "shadow" copy of the device configuration is kept so we can +** just set each mapping to what the local copy says. +** +** This function ALWAYS updates the local shadow configuration of +** the device function being enabled, even if the device is always +** enabled. To avoid replication of code, functions such as +** configure_device set up the local copy and then call this +** function to the update the real device. +** +**-- +*/ +unsigned int __init SMC37c669_enable_device ( unsigned int func ) +{ + unsigned int ret_val = FALSE; +/* +** Put the device into configuration mode +*/ + SMC37c669_config_mode( TRUE ); + switch ( func ) { + case SERIAL_0: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Enable the serial 1 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart1_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Enable the serial 1 port base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3; + + SMC37c669_write_config( + SMC37c669_SERIAL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case SERIAL_1: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Enable the serial 2 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart2_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Enable the serial 2 port base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3; + + SMC37c669_write_config( + SMC37c669_SERIAL1_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case PARALLEL_0: + { + SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Enable the parallel port DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.ppt_drq = + SMC37c669_RAW_DEVICE_DRQ( + SMC37c669_xlate_drq( local_config[ func ].drq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Enable the parallel port IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.ppt_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Enable the parallel port base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_2 = local_config[ func ].port1 >> 2; + + SMC37c669_write_config( + SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case FLOPPY_0: + { + SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Enable the floppy controller DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.fdc_drq = + SMC37c669_RAW_DEVICE_DRQ( + SMC37c669_xlate_drq( local_config[ func ].drq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Enable the floppy controller IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.fdc_irq = + SMC37c669_RAW_DEVICE_IRQ( + SMC37c669_xlate_irq( local_config[ func ].irq ) + ); + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Enable the floppy controller base address mapping +*/ + base_addr.as_uchar = 0; + base_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4; + + SMC37c669_write_config( + SMC37c669_FDC_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case IDE_0: + { + SMC37c669_IDE_ADDRESS_REGISTER ide_addr; +/* +** Enable the IDE alternate status base address mapping +*/ + ide_addr.as_uchar = 0; + ide_addr.by_field.addr9_4 = local_config[ func ].port2 >> 4; + + SMC37c669_write_config( + SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX, + ide_addr.as_uchar + ); +/* +** Enable the IDE controller base address mapping +*/ + ide_addr.as_uchar = 0; + ide_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4; + + SMC37c669_write_config( + SMC37c669_IDE_BASE_ADDRESS_INDEX, + ide_addr.as_uchar + ); + ret_val = TRUE; + break; + } + } +/* +** Exit configuration mode and return +*/ + SMC37c669_config_mode( FALSE ); + + return ret_val; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function disables a device function within the +** SMC37c669 Super I/O controller. +** +** FORMAL PARAMETERS: +** +** func: +** Which function to disable +** +** RETURN VALUE: +** +** Return TRUE if the device function was disabled, otherwise, FALSE +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** Disabling a function in the SMC37c669 device involves +** disabling all the function's mappings (port, irq, drq ...). +** A shadow copy of the device configuration is maintained +** in local storage so we won't worry aboving saving the +** current configuration information. +** +**-- +*/ +unsigned int __init SMC37c669_disable_device ( unsigned int func ) +{ + unsigned int ret_val = FALSE; + +/* +** Put the device into configuration mode +*/ + SMC37c669_config_mode( TRUE ); + switch ( func ) { + case SERIAL_0: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Disable the serial 1 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart1_irq = 0; + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Disable the serial 1 port base address mapping +*/ + base_addr.as_uchar = 0; + SMC37c669_write_config( + SMC37c669_SERIAL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case SERIAL_1: + { + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_SERIAL_IRQ_REGISTER irq; +/* +** Disable the serial 2 IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); + + irq.by_field.uart2_irq = 0; + + SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar ); +/* +** Disable the serial 2 port base address mapping +*/ + base_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_SERIAL1_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case PARALLEL_0: + { + SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Disable the parallel port DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.ppt_drq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Disable the parallel port IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.ppt_irq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Disable the parallel port base address mapping +*/ + base_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case FLOPPY_0: + { + SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq; +/* +** Disable the floppy controller DMA channel mapping +*/ + drq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); + + drq.by_field.fdc_drq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_DRQ_INDEX, + drq.as_uchar + ); +/* +** Disable the floppy controller IRQ mapping +*/ + irq.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); + + irq.by_field.fdc_irq = 0; + + SMC37c669_write_config( + SMC37c669_PARALLEL_FDC_IRQ_INDEX, + irq.as_uchar + ); +/* +** Disable the floppy controller base address mapping +*/ + base_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_FDC_BASE_ADDRESS_INDEX, + base_addr.as_uchar + ); + ret_val = TRUE; + break; + } + case IDE_0: + { + SMC37c669_IDE_ADDRESS_REGISTER ide_addr; +/* +** Disable the IDE alternate status base address mapping +*/ + ide_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX, + ide_addr.as_uchar + ); +/* +** Disable the IDE controller base address mapping +*/ + ide_addr.as_uchar = 0; + + SMC37c669_write_config( + SMC37c669_IDE_BASE_ADDRESS_INDEX, + ide_addr.as_uchar + ); + ret_val = TRUE; + break; + } + } +/* +** Exit configuration mode and return +*/ + SMC37c669_config_mode( FALSE ); + + return ret_val; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function configures a device function within the +** SMC37c669 Super I/O controller. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** port: +** I/O port for the function to use +** +** irq: +** IRQ for the device function to use +** +** drq: +** DMA channel for the device function to use +** +** RETURN VALUE: +** +** Returns TRUE if the device function was configured, +** otherwise, FALSE. +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** If this function returns TRUE, the local shadow copy of +** the configuration is also updated. If the device function +** is currently disabled, only the local shadow copy is +** updated and the actual device function will be updated +** if/when is is enabled. +** +**-- +*/ +unsigned int __init SMC37c669_configure_device ( + unsigned int func, + int port, + int irq, + int drq ) +{ + struct DEVICE_CONFIG *cp; + +/* +** Check for a valid configuration +*/ + if ( ( cp = SMC37c669_get_config ( func ) ) != NULL ) { +/* +** Configuration is valid, update the local shadow copy +*/ + if ( ( drq & ~0xFF ) == 0 ) { + cp->drq = drq; + } + if ( ( irq & ~0xFF ) == 0 ) { + cp->irq = irq; + } + if ( ( port & ~0xFFFF ) == 0 ) { + cp->port1 = port; + } +/* +** If the device function is enabled, update the actual +** device configuration. +*/ + if ( SMC37c669_is_device_enabled( func ) ) { + SMC37c669_enable_device( func ); + } + return TRUE; + } + return FALSE; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function determines whether a device function +** within the SMC37c669 controller is enabled. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** RETURN VALUE: +** +** Returns TRUE if the device function is enabled, otherwise, FALSE +** +** SIDE EFFECTS: +** +** {@description or none@} +** +** DESIGN: +** +** To check whether a device is enabled we will only look at +** the port base address mapping. According to the SMC37c669 +** specification, all of the port base address mappings are +** disabled if the addr<9:8> (bits <7:6> of the register) are +** zero. +** +**-- +*/ +static unsigned int __init SMC37c669_is_device_enabled ( unsigned int func ) +{ + unsigned char base_addr = 0; + unsigned int dev_ok = FALSE; + unsigned int ret_val = FALSE; +/* +** Enter configuration mode +*/ + SMC37c669_config_mode( TRUE ); + + switch ( func ) { + case SERIAL_0: + base_addr = + SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case SERIAL_1: + base_addr = + SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case PARALLEL_0: + base_addr = + SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case FLOPPY_0: + base_addr = + SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + case IDE_0: + base_addr = + SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX ); + dev_ok = TRUE; + break; + } +/* +** If we have a valid device, check base_addr<7:6> to see if the +** device is enabled (mapped). +*/ + if ( ( dev_ok ) && ( ( base_addr & 0xC0 ) != 0 ) ) { +/* +** The mapping is not disabled, so assume that the function is +** enabled. +*/ + ret_val = TRUE; + } +/* +** Exit configuration mode +*/ + SMC37c669_config_mode( FALSE ); + + return ret_val; +} + + +#if 0 +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function retrieves the configuration information of a +** device function within the SMC37c699 Super I/O controller. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** port: +** I/O port returned +** +** irq: +** IRQ returned +** +** drq: +** DMA channel returned +** +** RETURN VALUE: +** +** Returns TRUE if the device configuration was successfully +** retrieved, otherwise, FALSE. +** +** SIDE EFFECTS: +** +** The data pointed to by the port, irq, and drq parameters +** my be modified even if the configuration is not successfully +** retrieved. +** +** DESIGN: +** +** The device configuration is fetched from the local shadow +** copy. Any unused parameters will be set to -1. Any +** parameter which is not desired can specify the NULL +** pointer. +** +**-- +*/ +static unsigned int __init SMC37c669_get_device_config ( + unsigned int func, + int *port, + int *irq, + int *drq ) +{ + struct DEVICE_CONFIG *cp; + unsigned int ret_val = FALSE; +/* +** Check for a valid device configuration +*/ + if ( ( cp = SMC37c669_get_config( func ) ) != NULL ) { + if ( drq != NULL ) { + *drq = cp->drq; + ret_val = TRUE; + } + if ( irq != NULL ) { + *irq = cp->irq; + ret_val = TRUE; + } + if ( port != NULL ) { + *port = cp->port1; + ret_val = TRUE; + } + } + return ret_val; +} +#endif + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function displays the current state of the SMC37c699 +** Super I/O controller's device functions. +** +** FORMAL PARAMETERS: +** +** None +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +void __init SMC37c669_display_device_info ( void ) +{ + if ( SMC37c669_is_device_enabled( SERIAL_0 ) ) { + printk( " Serial 0: Enabled [ Port 0x%x, IRQ %d ]\n", + local_config[ SERIAL_0 ].port1, + local_config[ SERIAL_0 ].irq + ); + } + else { + printk( " Serial 0: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( SERIAL_1 ) ) { + printk( " Serial 1: Enabled [ Port 0x%x, IRQ %d ]\n", + local_config[ SERIAL_1 ].port1, + local_config[ SERIAL_1 ].irq + ); + } + else { + printk( " Serial 1: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( PARALLEL_0 ) ) { + printk( " Parallel: Enabled [ Port 0x%x, IRQ %d/%d ]\n", + local_config[ PARALLEL_0 ].port1, + local_config[ PARALLEL_0 ].irq, + local_config[ PARALLEL_0 ].drq + ); + } + else { + printk( " Parallel: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( FLOPPY_0 ) ) { + printk( " Floppy Ctrl: Enabled [ Port 0x%x, IRQ %d/%d ]\n", + local_config[ FLOPPY_0 ].port1, + local_config[ FLOPPY_0 ].irq, + local_config[ FLOPPY_0 ].drq + ); + } + else { + printk( " Floppy Ctrl: Disabled\n" ); + } + + if ( SMC37c669_is_device_enabled( IDE_0 ) ) { + printk( " IDE 0: Enabled [ Port 0x%x, IRQ %d ]\n", + local_config[ IDE_0 ].port1, + local_config[ IDE_0 ].irq + ); + } + else { + printk( " IDE 0: Disabled\n" ); + } +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function puts the SMC37c669 Super I/O controller into, +** and takes it out of, configuration mode. +** +** FORMAL PARAMETERS: +** +** enable: +** TRUE to enter configuration mode, FALSE to exit. +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** The SMC37c669 controller may be left in configuration mode. +** +**-- +*/ +static void __init SMC37c669_config_mode( + unsigned int enable ) +{ + if ( enable ) { +/* +** To enter configuration mode, two writes in succession to the index +** port are required. If a write to another address or port occurs +** between these two writes, the chip does not enter configuration +** mode. Therefore, a spinlock is placed around the two writes to +** guarantee that they complete uninterrupted. +*/ + spinlock( &spl_atomic ); + wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY ); + wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY ); + spinunlock( &spl_atomic ); + } + else { + wb( &SMC37c669->index_port, SMC37c669_CONFIG_OFF_KEY ); + } +} + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function reads an SMC37c669 Super I/O controller +** configuration register. This function assumes that the +** device is already in configuration mode. +** +** FORMAL PARAMETERS: +** +** index: +** Index value of configuration register to read +** +** RETURN VALUE: +** +** Data read from configuration register +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +static unsigned char __init SMC37c669_read_config( + unsigned char index ) +{ + unsigned char data; + + wb( &SMC37c669->index_port, index ); + data = rb( &SMC37c669->data_port ); + return data; +} + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function writes an SMC37c669 Super I/O controller +** configuration register. This function assumes that the +** device is already in configuration mode. +** +** FORMAL PARAMETERS: +** +** index: +** Index of configuration register to write +** +** data: +** Data to be written +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** None +** +**-- +*/ +static void __init SMC37c669_write_config( + unsigned char index, + unsigned char data ) +{ + wb( &SMC37c669->index_port, index ); + wb( &SMC37c669->data_port, data ); +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function initializes the local device +** configuration storage. This function assumes +** that the device is already in configuration +** mode. +** +** FORMAL PARAMETERS: +** +** None +** +** RETURN VALUE: +** +** None +** +** SIDE EFFECTS: +** +** Local storage for device configuration information +** is initialized. +** +**-- +*/ +static void __init SMC37c669_init_local_config ( void ) +{ + SMC37c669_SERIAL_BASE_ADDRESS_REGISTER uart_base; + SMC37c669_SERIAL_IRQ_REGISTER uart_irqs; + SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER ppt_base; + SMC37c669_PARALLEL_FDC_IRQ_REGISTER ppt_fdc_irqs; + SMC37c669_PARALLEL_FDC_DRQ_REGISTER ppt_fdc_drqs; + SMC37c669_FDC_BASE_ADDRESS_REGISTER fdc_base; + SMC37c669_IDE_ADDRESS_REGISTER ide_base; + SMC37c669_IDE_ADDRESS_REGISTER ide_alt; + +/* +** Get serial port 1 base address +*/ + uart_base.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX ); +/* +** Get IRQs for serial ports 1 & 2 +*/ + uart_irqs.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX ); +/* +** Store local configuration information for serial port 1 +*/ + local_config[SERIAL_0].port1 = uart_base.by_field.addr9_3 << 3; + local_config[SERIAL_0].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart1_irq ) + ); +/* +** Get serial port 2 base address +*/ + uart_base.as_uchar = + SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX ); +/* +** Store local configuration information for serial port 2 +*/ + local_config[SERIAL_1].port1 = uart_base.by_field.addr9_3 << 3; + local_config[SERIAL_1].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart2_irq ) + ); +/* +** Get parallel port base address +*/ + ppt_base.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX ); +/* +** Get IRQs for parallel port and floppy controller +*/ + ppt_fdc_irqs.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX ); +/* +** Get DRQs for parallel port and floppy controller +*/ + ppt_fdc_drqs.as_uchar = + SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX ); +/* +** Store local configuration information for parallel port +*/ + local_config[PARALLEL_0].port1 = ppt_base.by_field.addr9_2 << 2; + local_config[PARALLEL_0].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.ppt_irq ) + ); + local_config[PARALLEL_0].drq = + SMC37c669_xlate_drq( + SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.ppt_drq ) + ); +/* +** Get floppy controller base address +*/ + fdc_base.as_uchar = + SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX ); +/* +** Store local configuration information for floppy controller +*/ + local_config[FLOPPY_0].port1 = fdc_base.by_field.addr9_4 << 4; + local_config[FLOPPY_0].irq = + SMC37c669_xlate_irq( + SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.fdc_irq ) + ); + local_config[FLOPPY_0].drq = + SMC37c669_xlate_drq( + SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.fdc_drq ) + ); +/* +** Get IDE controller base address +*/ + ide_base.as_uchar = + SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX ); +/* +** Get IDE alternate status base address +*/ + ide_alt.as_uchar = + SMC37c669_read_config( SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX ); +/* +** Store local configuration information for IDE controller +*/ + local_config[IDE_0].port1 = ide_base.by_field.addr9_4 << 4; + local_config[IDE_0].port2 = ide_alt.by_field.addr9_4 << 4; + local_config[IDE_0].irq = 14; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function returns a pointer to the local shadow +** configuration of the requested device function. +** +** FORMAL PARAMETERS: +** +** func: +** Which device function +** +** RETURN VALUE: +** +** Returns a pointer to the DEVICE_CONFIG structure for the +** requested function, otherwise, NULL. +** +** SIDE EFFECTS: +** +** {@description or none@} +** +**-- +*/ +static struct DEVICE_CONFIG * __init SMC37c669_get_config( unsigned int func ) +{ + struct DEVICE_CONFIG *cp = NULL; + + switch ( func ) { + case SERIAL_0: + cp = &local_config[ SERIAL_0 ]; + break; + case SERIAL_1: + cp = &local_config[ SERIAL_1 ]; + break; + case PARALLEL_0: + cp = &local_config[ PARALLEL_0 ]; + break; + case FLOPPY_0: + cp = &local_config[ FLOPPY_0 ]; + break; + case IDE_0: + cp = &local_config[ IDE_0 ]; + break; + } + return cp; +} + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function translates IRQs back and forth between ISA +** IRQs and SMC37c669 device IRQs. +** +** FORMAL PARAMETERS: +** +** irq: +** The IRQ to translate +** +** RETURN VALUE: +** +** Returns the translated IRQ, otherwise, returns -1. +** +** SIDE EFFECTS: +** +** {@description or none@} +** +**-- +*/ +static int __init SMC37c669_xlate_irq ( unsigned int irq ) +{ + int i, translated_irq = -1; + + if ( SMC37c669_IS_DEVICE_IRQ( irq ) ) { +/* +** We are translating a device IRQ to an ISA IRQ +*/ + for ( i = 0; ( SMC37c669_irq_table[i].device_irq != -1 ) || ( SMC37c669_irq_table[i].isa_irq != -1 ); i++ ) { + if ( irq == SMC37c669_irq_table[i].device_irq ) { + translated_irq = SMC37c669_irq_table[i].isa_irq; + break; + } + } + } + else { +/* +** We are translating an ISA IRQ to a device IRQ +*/ + for ( i = 0; ( SMC37c669_irq_table[i].isa_irq != -1 ) || ( SMC37c669_irq_table[i].device_irq != -1 ); i++ ) { + if ( irq == SMC37c669_irq_table[i].isa_irq ) { + translated_irq = SMC37c669_irq_table[i].device_irq; + break; + } + } + } + return translated_irq; +} + + +/* +**++ +** FUNCTIONAL DESCRIPTION: +** +** This function translates DMA channels back and forth between +** ISA DMA channels and SMC37c669 device DMA channels. +** +** FORMAL PARAMETERS: +** +** drq: +** The DMA channel to translate +** +** RETURN VALUE: +** +** Returns the translated DMA channel, otherwise, returns -1 +** +** SIDE EFFECTS: +** +** {@description or none@} +** +**-- +*/ +static int __init SMC37c669_xlate_drq ( unsigned int drq ) +{ + int i, translated_drq = -1; + + if ( SMC37c669_IS_DEVICE_DRQ( drq ) ) { +/* +** We are translating a device DMA channel to an ISA DMA channel +*/ + for ( i = 0; ( SMC37c669_drq_table[i].device_drq != -1 ) || ( SMC37c669_drq_table[i].isa_drq != -1 ); i++ ) { + if ( drq == SMC37c669_drq_table[i].device_drq ) { + translated_drq = SMC37c669_drq_table[i].isa_drq; + break; + } + } + } + else { +/* +** We are translating an ISA DMA channel to a device DMA channel +*/ + for ( i = 0; ( SMC37c669_drq_table[i].isa_drq != -1 ) || ( SMC37c669_drq_table[i].device_drq != -1 ); i++ ) { + if ( drq == SMC37c669_drq_table[i].isa_drq ) { + translated_drq = SMC37c669_drq_table[i].device_drq; + break; + } + } + } + return translated_drq; +} + +#if 0 +int __init smcc669_init ( void ) +{ + struct INODE *ip; + + allocinode( smc_ddb.name, 1, &ip ); + ip->dva = &smc_ddb; + ip->attr = ATTR$M_WRITE | ATTR$M_READ; + ip->len[0] = 0x30; + ip->misc = 0; + INODE_UNLOCK( ip ); + + return msg_success; +} + +int __init smcc669_open( struct FILE *fp, char *info, char *next, char *mode ) +{ + struct INODE *ip; +/* +** Allow multiple readers but only one writer. ip->misc keeps track +** of the number of writers +*/ + ip = fp->ip; + INODE_LOCK( ip ); + if ( fp->mode & ATTR$M_WRITE ) { + if ( ip->misc ) { + INODE_UNLOCK( ip ); + return msg_failure; /* too many writers */ + } + ip->misc++; + } +/* +** Treat the information field as a byte offset +*/ + *fp->offset = xtoi( info ); + INODE_UNLOCK( ip ); + + return msg_success; +} + +int __init smcc669_close( struct FILE *fp ) +{ + struct INODE *ip; + + ip = fp->ip; + if ( fp->mode & ATTR$M_WRITE ) { + INODE_LOCK( ip ); + ip->misc--; + INODE_UNLOCK( ip ); + } + return msg_success; +} + +int __init smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf ) +{ + int i; + int length; + int nbytes; + struct INODE *ip; + +/* +** Always access a byte at a time +*/ + ip = fp->ip; + length = size * number; + nbytes = 0; + + SMC37c669_config_mode( TRUE ); + for ( i = 0; i < length; i++ ) { + if ( !inrange( *fp->offset, 0, ip->len[0] ) ) + break; + *buf++ = SMC37c669_read_config( *fp->offset ); + *fp->offset += 1; + nbytes++; + } + SMC37c669_config_mode( FALSE ); + return nbytes; +} + +int __init smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf ) +{ + int i; + int length; + int nbytes; + struct INODE *ip; +/* +** Always access a byte at a time +*/ + ip = fp->ip; + length = size * number; + nbytes = 0; + + SMC37c669_config_mode( TRUE ); + for ( i = 0; i < length; i++ ) { + if ( !inrange( *fp->offset, 0, ip->len[0] ) ) + break; + SMC37c669_write_config( *fp->offset, *buf ); + *fp->offset += 1; + buf++; + nbytes++; + } + SMC37c669_config_mode( FALSE ); + return nbytes; +} +#endif + +void __init +SMC37c669_dump_registers(void) +{ + int i; + for (i = 0; i <= 0x29; i++) + printk("-- CR%02x : %02x\n", i, SMC37c669_read_config(i)); +} +/*+ + * ============================================================================ + * = SMC_init - SMC37c669 Super I/O controller initialization = + * ============================================================================ + * + * OVERVIEW: + * + * This routine configures and enables device functions on the + * SMC37c669 Super I/O controller. + * + * FORM OF CALL: + * + * SMC_init( ); + * + * RETURNS: + * + * Nothing + * + * ARGUMENTS: + * + * None + * + * SIDE EFFECTS: + * + * None + * + */ +void __init SMC669_Init ( void ) +{ + SMC37c669_CONFIG_REGS *SMC_base; + + if ( ( SMC_base = SMC37c669_detect( ) ) != NULL ) { + printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n", + (unsigned long) SMC_base ); +#if SMC_DEBUG + SMC37c669_config_mode( TRUE ); + SMC37c669_dump_registers( ); + SMC37c669_config_mode( FALSE ); + SMC37c669_display_device_info( ); +#endif + SMC37c669_disable_device( SERIAL_0 ); + SMC37c669_configure_device( + SERIAL_0, + COM1_BASE, + COM1_IRQ, + -1 + ); + SMC37c669_enable_device( SERIAL_0 ); + + SMC37c669_disable_device( SERIAL_1 ); + SMC37c669_configure_device( + SERIAL_1, + COM2_BASE, + COM2_IRQ, + -1 + ); + SMC37c669_enable_device( SERIAL_1 ); + + SMC37c669_disable_device( PARALLEL_0 ); + SMC37c669_configure_device( + PARALLEL_0, + PARP_BASE, + PARP_IRQ, + PARP_DRQ + ); + SMC37c669_enable_device( PARALLEL_0 ); + + SMC37c669_disable_device( FLOPPY_0 ); + SMC37c669_configure_device( + FLOPPY_0, + FDC_BASE, + FDC_IRQ, + FDC_DRQ + ); + SMC37c669_enable_device( FLOPPY_0 ); + + SMC37c669_disable_device( IDE_0 ); + +#if SMC_DEBUG + SMC37c669_config_mode( TRUE ); + SMC37c669_dump_registers( ); + SMC37c669_config_mode( FALSE ); + SMC37c669_display_device_info( ); +#endif + } + else { +#if SMC_DEBUG + printk( "No SMC37c669 Super I/O Controller found\n" ); +#endif + } +} diff -ur --new-file old/linux/arch/alpha/kernel/smc37c93x.c new/linux/arch/alpha/kernel/smc37c93x.c --- old/linux/arch/alpha/kernel/smc37c93x.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/kernel/smc37c93x.c Mon Feb 23 19:25:10 1998 @@ -0,0 +1,264 @@ +/* + * SMC 37C93X initialization code + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +/* device "activate" register contents */ +#define DEVICE_ON 1 +#define DEVICE_OFF 0 + +/* configuration on/off keys */ +#define CONFIG_ON_KEY 0x55 +#define CONFIG_OFF_KEY 0xaa + +/* configuration space device definitions */ +#define FDC 0 +#define IDE1 1 +#define IDE2 2 +#define PARP 3 +#define SER1 4 +#define SER2 5 +#define RTCL 6 +#define KYBD 7 +#define AUXIO 8 + +/* Chip register offsets from base */ +#define CONFIG_CONTROL 0x02 +#define INDEX_ADDRESS 0x03 +#define LOGICAL_DEVICE_NUMBER 0x07 +#define DEVICE_ID 0x20 +#define DEVICE_REV 0x21 +#define POWER_CONTROL 0x22 +#define POWER_MGMT 0x23 +#define OSC 0x24 + +#define ACTIVATE 0x30 +#define ADDR_HI 0x60 +#define ADDR_LO 0x61 +#define INTERRUPT_SEL 0x70 +#define INTERRUPT_SEL_2 0x72 /* KYBD/MOUS only */ +#define DMA_CHANNEL_SEL 0x74 /* FDC/PARP only */ + +#define FDD_MODE_REGISTER 0x90 +#define FDD_OPTION_REGISTER 0x91 + +/* values that we read back that are expected ... */ +#define VALID_DEVICE_ID 2 + +/* default device addresses */ +#define KYBD_INTERRUPT 1 +#define MOUS_INTERRUPT 12 +#define COM2_BASE 0x2f8 +#define COM2_INTERRUPT 3 +#define COM1_BASE 0x3f8 +#define COM1_INTERRUPT 4 +#define PARP_BASE 0x3bc +#define PARP_INTERRUPT 7 + +#define SMC_DEBUG 0 + +static unsigned long __init SMCConfigState(unsigned long baseAddr) +{ + unsigned char devId; + unsigned char devRev; + + unsigned long configPort; + unsigned long indexPort; + unsigned long dataPort; + + configPort = indexPort = baseAddr; + dataPort = configPort + 1; + + outb(CONFIG_ON_KEY, configPort); + outb(CONFIG_ON_KEY, configPort); + outb(DEVICE_ID, indexPort); + devId = inb(dataPort); + if ( devId == VALID_DEVICE_ID ) { + outb(DEVICE_REV, indexPort); + devRev = inb(dataPort); + } + else { + baseAddr = 0; + } + return baseAddr; +} + +static void __init SMCRunState(unsigned long baseAddr) +{ + outb(CONFIG_OFF_KEY, baseAddr); +} + +static unsigned long __init SMCDetectUltraIO(void) +{ + unsigned long baseAddr; + + baseAddr = 0x3F0; + if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) { + return( baseAddr ); + } + baseAddr = 0x370; + if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) { + return( baseAddr ); + } + return( ( unsigned long )0 ); +} + +static void __init SMCEnableDevice(unsigned long baseAddr, + unsigned long device, + unsigned long portaddr, + unsigned long interrupt) +{ + unsigned long indexPort; + unsigned long dataPort; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(device, dataPort); + + outb(ADDR_LO, indexPort); + outb(( portaddr & 0xFF ), dataPort); + + outb(ADDR_HI, indexPort); + outb((portaddr >> 8) & 0xFF, dataPort); + + outb(INTERRUPT_SEL, indexPort); + outb(interrupt, dataPort); + + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); +} + +static void __init SMCEnableKYBD(unsigned long baseAddr) +{ + unsigned long indexPort; + unsigned long dataPort; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(KYBD, dataPort); + + outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ + outb(KYBD_INTERRUPT, dataPort); + + outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */ + outb(MOUS_INTERRUPT, dataPort); + + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); +} + +static void __init SMCEnableFDC(unsigned long baseAddr) +{ + unsigned long indexPort; + unsigned long dataPort; + + unsigned char oldValue; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(LOGICAL_DEVICE_NUMBER, indexPort); + outb(FDC, dataPort); + + outb(FDD_MODE_REGISTER, indexPort); + oldValue = inb(dataPort); + + oldValue |= 0x0E; /* Enable burst mode */ + outb(oldValue, dataPort); + + outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */ + outb(0x06, dataPort ); + + outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */ + outb(0x02, dataPort); + + outb(ACTIVATE, indexPort); + outb(DEVICE_ON, dataPort); +} + +#if SMC_DEBUG +static void __init SMCReportDeviceStatus(unsigned long baseAddr) +{ + unsigned long indexPort; + unsigned long dataPort; + unsigned char currentControl; + + indexPort = baseAddr; + dataPort = baseAddr + 1; + + outb(POWER_CONTROL, indexPort); + currentControl = inb(dataPort); + + printk(currentControl & (1 << FDC) + ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n"); + printk(currentControl & (1 << IDE1) + ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n"); + printk(currentControl & (1 << IDE2) + ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n"); + printk(currentControl & (1 << PARP) + ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n"); + printk(currentControl & (1 << SER1) + ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n"); + printk(currentControl & (1 << SER2) + ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n"); + + printk( "\n" ); +} +#endif + +int __init SMC93x_Init(void) +{ + unsigned long SMCUltraBase; + + if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) { + printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", + SMCUltraBase); +#if SMC_DEBUG + SMCReportDeviceStatus(SMCUltraBase); +#endif + SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT); + SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT); + SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT); + /* On PC164, IDE on the SMC is not enabled; + CMD646 (PCI) on MB */ + SMCEnableKYBD(SMCUltraBase); + SMCEnableFDC(SMCUltraBase); +#if SMC_DEBUG + SMCReportDeviceStatus(SMCUltraBase); +#endif + SMCRunState(SMCUltraBase); + return 1; + } + else { +#if SMC_DEBUG + printk("No SMC FDC37C93X Ultra I/O Controller found\n"); +#endif + return 0; + } +} diff -ur --new-file old/linux/arch/alpha/kernel/t2.c new/linux/arch/alpha/kernel/t2.c --- old/linux/arch/alpha/kernel/t2.c Mon Jan 12 23:51:14 1998 +++ new/linux/arch/alpha/kernel/t2.c Sat Feb 21 03:28:21 1998 @@ -8,7 +8,6 @@ * */ #include -#include #include #include #include @@ -20,6 +19,10 @@ #include #include +/* NOTE: Herein are back-to-back mb insns. They are magic. + A plausable explanation is that the i/o controler does not properly + handle the system transaction. Another involves timing. Ho hum. */ + extern struct hwrpb_struct *hwrpb; extern asmlinkage void wrmces(unsigned long mces); extern asmlinkage unsigned long whami(void); @@ -173,6 +176,7 @@ /* access configuration space: */ value = *(vuip)addr; mb(); + mb(); /* magic */ if (T2_mcheck_taken) { T2_mcheck_taken = 0; value = 0xffffffffU; @@ -226,6 +230,7 @@ /* access configuration space: */ *(vuip)addr = value; mb(); + mb(); /* magic */ T2_mcheck_expected = 0; mb(); @@ -480,6 +485,7 @@ *(vulp)T2_PERR1 |= *(vulp)T2_PERR1; mb(); + mb(); /* magic */ return 0; } @@ -530,12 +536,14 @@ * ignore the machine check. */ mb(); + mb(); /* magic */ if (T2_mcheck_expected/* && (mchk_sysdata->epic_dcsr && 0x0c00UL)*/) { DBGMC(("T2 machine check expected\n")); T2_mcheck_taken = 1; t2_clear_errors(); T2_mcheck_expected = 0; mb(); + mb(); /* magic */ wrmces(rdmces()|1);/* ??? */ draina(); return; 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 Sun Nov 30 19:59:02 1997 +++ new/linux/arch/alpha/kernel/traps.c Thu Feb 12 22:31:28 1998 @@ -105,14 +105,24 @@ do_exit(SIGSEGV); } +#ifndef CONFIG_MATHEMU +static long dummy_alpha_fp_emul_imprecise(struct pt_regs *r, unsigned long wm) +{ + return 0; +} + +long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask) + = dummy_alpha_fp_emul_imprecise; +#else +long alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask); +#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) { if ((summary & 1)) { - extern long alpha_fp_emul_imprecise (struct pt_regs * regs, - unsigned long write_mask); /* * Software-completion summary bit is set, so try to * emulate the instruction. @@ -863,9 +873,9 @@ unsigned long a4, unsigned long a5, struct pt_regs regs) { - /* Only report OSF system calls. */ - if (regs.r0 != 112 && regs.r0 < 300) - printk("", regs.r0, a0, a1, a2); + /* We only get here for OSF system calls, minus #112; + the rest go to sys_ni_syscall. */ + printk("", regs.r0, a0, a1, a2); return -ENOSYS; } diff -ur --new-file old/linux/arch/alpha/lib/Makefile new/linux/arch/alpha/lib/Makefile --- old/linux/arch/alpha/lib/Makefile Sun Nov 30 19:59:02 1997 +++ new/linux/arch/alpha/lib/Makefile Fri Feb 6 19:06:55 1998 @@ -6,15 +6,8 @@ checksum.o csum_partial_copy.o strlen.o \ strcat.o strcpy.o strncat.o strncpy.o stxcpy.o stxncpy.o \ strchr.o strrchr.o \ - copy_user.o clear_user.o strncpy_from_user.o strlen_user.o - -ifeq ($(CONFIG_IPV6),y) - OBJS += csum_ipv6_magic.o -else - ifeq ($(CONFIG_IPV6),m) - OBJS += csum_ipv6_magic.o - endif -endif + copy_user.o clear_user.o strncpy_from_user.o strlen_user.o \ + csum_ipv6_magic.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff -ur --new-file old/linux/arch/alpha/lib/csum_partial_copy.c new/linux/arch/alpha/lib/csum_partial_copy.c --- old/linux/arch/alpha/lib/csum_partial_copy.c Sun Nov 30 19:59:02 1997 +++ new/linux/arch/alpha/lib/csum_partial_copy.c Thu Jan 22 02:46:00 1998 @@ -112,7 +112,7 @@ * easy. */ static inline unsigned long -csum_partial_cfu_dest_aligned(unsigned long *src, unsigned long *dst, +csum_partial_cfu_dest_aligned(const unsigned long *src, unsigned long *dst, unsigned long soff, long len, unsigned long checksum, int *errp) diff -ur --new-file old/linux/arch/alpha/math-emu/Makefile new/linux/arch/alpha/math-emu/Makefile --- old/linux/arch/alpha/math-emu/Makefile Fri Dec 22 07:22:05 1995 +++ new/linux/arch/alpha/math-emu/Makefile Thu Feb 12 22:31:28 1998 @@ -2,11 +2,11 @@ # Makefile for math-emulator files... # -OBJS = fp-emul.o ieee-math.o +O_TARGET := math-emu.o +O_OBJS := fp-emul.o ieee-math.o -math-emu.a: $(OBJS) - $(AR) rcs $@ $(OBJS) - -dep: +ifeq ($(CONFIG_MATHEMU),m) +M_OBJS := $(O_TARGET) +endif include $(TOPDIR)/Rules.make 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 Tue Jun 17 01:35:53 1997 +++ new/linux/arch/alpha/math-emu/fp-emul.c Thu Feb 12 22:31:28 1998 @@ -1,5 +1,5 @@ +#include #include - #include #include @@ -52,111 +52,33 @@ #define MISC_TRAPB 0x0000 #define MISC_EXCB 0x0400 - -extern unsigned long rdfpcr (void); -extern void wrfpcr (unsigned long); +extern unsigned long alpha_read_fp_reg (unsigned long reg); +extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); -unsigned long -alpha_read_fp_reg (unsigned long reg) -{ - unsigned long r; +#ifdef MODULE - switch (reg) { - case 0: asm ("stt $f0,%0" : "m="(r)); break; - case 1: asm ("stt $f1,%0" : "m="(r)); break; - case 2: asm ("stt $f2,%0" : "m="(r)); break; - case 3: asm ("stt $f3,%0" : "m="(r)); break; - case 4: asm ("stt $f4,%0" : "m="(r)); break; - case 5: asm ("stt $f5,%0" : "m="(r)); break; - case 6: asm ("stt $f6,%0" : "m="(r)); break; - case 7: asm ("stt $f7,%0" : "m="(r)); break; - case 8: asm ("stt $f8,%0" : "m="(r)); break; - case 9: asm ("stt $f9,%0" : "m="(r)); break; - case 10: asm ("stt $f10,%0" : "m="(r)); break; - case 11: asm ("stt $f11,%0" : "m="(r)); break; - case 12: asm ("stt $f12,%0" : "m="(r)); break; - case 13: asm ("stt $f13,%0" : "m="(r)); break; - case 14: asm ("stt $f14,%0" : "m="(r)); break; - case 15: asm ("stt $f15,%0" : "m="(r)); break; - case 16: asm ("stt $f16,%0" : "m="(r)); break; - case 17: asm ("stt $f17,%0" : "m="(r)); break; - case 18: asm ("stt $f18,%0" : "m="(r)); break; - case 19: asm ("stt $f19,%0" : "m="(r)); break; - case 20: asm ("stt $f20,%0" : "m="(r)); break; - case 21: asm ("stt $f21,%0" : "m="(r)); break; - case 22: asm ("stt $f22,%0" : "m="(r)); break; - case 23: asm ("stt $f23,%0" : "m="(r)); break; - case 24: asm ("stt $f24,%0" : "m="(r)); break; - case 25: asm ("stt $f25,%0" : "m="(r)); break; - case 26: asm ("stt $f26,%0" : "m="(r)); break; - case 27: asm ("stt $f27,%0" : "m="(r)); break; - case 28: asm ("stt $f28,%0" : "m="(r)); break; - case 29: asm ("stt $f29,%0" : "m="(r)); break; - case 30: asm ("stt $f30,%0" : "m="(r)); break; - case 31: asm ("stt $f31,%0" : "m="(r)); break; - default: - break; - } - return r; -} +MODULE_DESCRIPTION("FP Software completion module"); +extern long (*alpha_fp_emul_imprecise)(struct pt_regs *, unsigned long); +static long (*save_emul)(struct pt_regs *, unsigned long); +long do_alpha_fp_emul_imprecise(struct pt_regs *, unsigned long); -#if 0 -/* - * This is IMHO the better way of implementing LDT(). But it - * has the disadvantage that gcc 2.7.0 refuses to compile it - * (invalid operand constraints), so instead, we use the uglier - * macro below. - */ -# define LDT(reg,val) \ - asm volatile ("ldt $f"#reg",%0" :: "m"(val)); -#else -# define LDT(reg,val) \ - asm volatile ("ldt $f"#reg",0(%0)" :: "r"(&val)); -#endif +int init_module(void) +{ + save_emul = alpha_fp_emul_imprecise; + alpha_fp_emul_imprecise = do_alpha_fp_emul_imprecise; + return 0; +} -void -alpha_write_fp_reg (unsigned long reg, unsigned long val) +void cleanup_module(void) { - switch (reg) { - case 0: LDT( 0, val); break; - case 1: LDT( 1, val); break; - case 2: LDT( 2, val); break; - case 3: LDT( 3, val); break; - case 4: LDT( 4, val); break; - case 5: LDT( 5, val); break; - case 6: LDT( 6, val); break; - case 7: LDT( 7, val); break; - case 8: LDT( 8, val); break; - case 9: LDT( 9, val); break; - case 10: LDT(10, val); break; - case 11: LDT(11, val); break; - case 12: LDT(12, val); break; - case 13: LDT(13, val); break; - case 14: LDT(14, val); break; - case 15: LDT(15, val); break; - case 16: LDT(16, val); break; - case 17: LDT(17, val); break; - case 18: LDT(18, val); break; - case 19: LDT(19, val); break; - case 20: LDT(20, val); break; - case 21: LDT(21, val); break; - case 22: LDT(22, val); break; - case 23: LDT(23, val); break; - case 24: LDT(24, val); break; - case 25: LDT(25, val); break; - case 26: LDT(26, val); break; - case 27: LDT(27, val); break; - case 28: LDT(28, val); break; - case 29: LDT(29, val); break; - case 30: LDT(30, val); break; - case 31: LDT(31, val); break; - default: - break; - } + alpha_fp_emul_imprecise = save_emul; } +#define alpha_fp_emul_imprecise do_alpha_fp_emul_imprecise + +#endif /* MODULE */ /* * Emulate the floating point instruction at address PC. Returns 0 if @@ -334,6 +256,8 @@ unsigned long trigger_pc = regs->pc - 4; unsigned long insn, opcode, rc; + MOD_INC_USE_COUNT; + /* * Turn off the bits corresponding to registers that are the * target of instructions that set bits in the exception @@ -354,12 +278,14 @@ case OPC_PAL: case OPC_JSR: case 0x30 ... 0x3f: /* branches */ + MOD_DEC_USE_COUNT; return 0; case OPC_MISC: switch (insn & 0xffff) { case MISC_TRAPB: case MISC_EXCB: + MOD_DEC_USE_COUNT; return 0; default: @@ -386,11 +312,13 @@ { /* re-execute insns in trap-shadow: */ regs->pc = trigger_pc + 4; + MOD_DEC_USE_COUNT; return 1; } break; } trigger_pc -= 4; } + MOD_DEC_USE_COUNT; return 0; } 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 Fri Apr 12 08:49:30 1996 +++ new/linux/arch/alpha/math-emu/ieee-math.c Sun Mar 1 07:11:02 1998 @@ -137,9 +137,8 @@ static inline void mul64 (const unsigned long a, const unsigned long b, unsigned long c[2]) { - asm ("mulq %2,%3,%0\n\t" - "umulh %2,%3,%1" - : "r="(c[0]), "r="(c[1]) : "r"(a), "r"(b)); + c[0] = a * b; + asm ("umulh %1,%2,%0" : "=r"(c[1]) : "r"(a), "r"(b)); } @@ -276,7 +275,7 @@ { unsigned long res, sticky; - if (!a->f[0] && !a->f[1]) { + if (!a->e && !a->f[0] && !a->f[1]) { *b = (unsigned long) a->s << 63; /* return +/-0 */ return 0; } @@ -356,7 +355,7 @@ { unsigned long res, sticky; - if (!a->f[0] && !a->f[1]) { + if (!a->e && !a->f[0] && !a->f[1]) { *b = (unsigned long) a->s << 63; /* return +/-0 */ return 0; } @@ -384,7 +383,7 @@ a->e = -0x3ff; } } - if (a->e > 0x3ff) { + if (a->e >= 0x3ff) { res = FPCR_OVF | FPCR_INE; if (f & IEEE_TRAP_ENABLE_OVF) { a->e -= 0x600; /* scale down result by 2^alpha */ @@ -777,25 +776,25 @@ midway = (temp.f[0] & 0x003fffffffffffff) == 0; if ((midway && (temp.f[0] & 0x0080000000000000)) || !midway) - ++b; + ++*b; } break; case ROUND_PINF: - if ((temp.f[0] & 0x003fffffffffffff) != 0) - ++b; + if ((temp.f[0] & 0x007fffffffffffff) != 0) + ++*b; break; case ROUND_NINF: - if ((temp.f[0] & 0x003fffffffffffff) != 0) - --b; + if ((temp.f[0] & 0x007fffffffffffff) != 0) + --*b; break; case ROUND_CHOP: /* no action needed */ break; } - if ((temp.f[0] & 0x003fffffffffffff) != 0) + if ((temp.f[0] & 0x007fffffffffffff) != 0) res |= FPCR_INE; if (temp.s) { @@ -1143,12 +1142,9 @@ return 0; } op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e + op_b.e; + op_c.e = op_a.e + op_b.e - 55; mul64(op_a.f[0], op_b.f[0], op_c.f); - normalize(&op_c); - op_c.e -= 55; /* drop the 55 original bits. */ - return round_s_ieee(f, &op_c, c); } @@ -1200,11 +1196,8 @@ return 0; } op_c.s = op_a.s ^ op_b.s; - op_c.e = op_a.e + op_b.e; + op_c.e = op_a.e + op_b.e - 55; mul64(op_a.f[0], op_b.f[0], op_c.f); - - normalize(&op_c); - op_c.e -= 55; /* drop the 55 original bits. */ return round_t_ieee(f, &op_c, c); } diff -ur --new-file old/linux/arch/arm/Makefile new/linux/arch/arm/Makefile --- old/linux/arch/arm/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/Makefile Wed Jan 21 01:39:41 1998 @@ -0,0 +1,198 @@ +# +# arch/arm/Makefile +# +# This file is included by the global makefile so that you can add your own +# architecture-specific flags and dependencies. Remember to do have actions +# for "archclean" and "archdep" for cleaning up and making dependencies for +# this architecture +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995, 1996 by Russell King + +ifeq ($(CONFIG_CPU_ARM2),y) +PROCESSOR = armo +ASFLAGS_PROC += -m2 +ifeq ($(CONFIG_BINUTILS_NEW),y) +CFLAGS_PROC += -mcpu=arm2 +ASFLAGS_PROC += -m2 +else +CFLAGS_PROC += -m2 +ASFLAGS_PROC += -m2 +endif +endif + +ifeq ($(CONFIG_CPU_ARM3),y) +PROCESSOR = armo +ifeq ($(CONFIG_BINUTILS_NEW),y) +CFLAGS_PROC += -mcpu=arm3 +ASFLAGS_PROC += -m3 +else +CFLAGS_PROC += -m3 +ASFLAGS_PROC += -m3 +endif +endif + +ifeq ($(CONFIG_CPU_ARM6),y) +PROCESSOR = armv +ifeq ($(CONFIG_BINUTILS_NEW),y) +CFLAGS_PROC += -mcpu=arm6 +ASFLAGS_PROC += -m6 +else +CFLAGS_PROC += -m6 +ASFLAGS_PROC += -m6 +endif +endif + +ifeq ($(CONFIG_CPU_SA110),y) +PROCESSOR = armv +ifeq ($(CONFIG_BINUTILS_NEW),y) +CFLAGS_PROC += -mcpu=strongarm110 +ASFLAGS_PROC += -m6 +else +CFLAGS_PROC += -m6 +ASFLAGS_PROC += -m6 +endif +endif + +# Processor Architecture +# CFLAGS_PROC - processor dependent CFLAGS +# PROCESSOR - processor type +# TEXTADDR - Uncompressed kernel link text address +# ZTEXTADDR - Compressed kernel link text address +# ZRELADDR - Compressed kernel relocating address (point at which uncompressed kernel is loaded). +# + +HEAD := arch/arm/kernel/head-$(PROCESSOR).o arch/arm/kernel/init_task.o +COMPRESSED_HEAD = head.o + +ifeq ($(PROCESSOR),armo) +ifeq ($(CONFIG_BINUTILS_NEW),y) +CFLAGS_PROC += -mapcs-26 -mshort-load-bytes +endif +TEXTADDR = 0x02080000 +ZTEXTADDR = 0x01800000 +ZRELADDR = 0x02080000 +endif + +ifeq ($(CONFIG_ARCH_A5K),y) +MACHINE = a5k +COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o +endif + +ifeq ($(CONFIG_ARCH_ARC),y) +MACHINE = arc +COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o +endif + +ifeq ($(PROCESSOR),armv) +ifeq ($(CONFIG_BINUTILS_NEW),y) +CFLAGS_PROC += -mapcs-32 -mshort-load-bytes +endif +TEXTADDR = 0xC0008000 +endif + +ifeq ($(CONFIG_ARCH_RPC),y) +MACHINE = rpc +COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr.o +ZTEXTADDR = 0x10008000 +ZRELADDR = 0x10008000 +endif + +ifeq ($(CONFIG_ARCH_EBSA110),y) +MACHINE = ebsa110 +ZTEXTADDR = 0x00008000 +ZRELADDR = 0x00008000 +endif + +ifeq ($(CONFIG_ARCH_NEXUSPCI),y) +MACHINE = nexuspci +TEXTADDR = 0xc0000000 +ZTEXTADDR = 0x40200000 +ZRELADDR = 0x40000000 +COMPRESSED_EXTRA = $(TOPDIR)/arch/arm/lib/ll_char_wr_scc.o +COMPRESSED_HEAD = head-nexuspci.o +endif + +OBJDUMP = $(CROSS_COMPILE)objdump +PERL = perl +LD = $(CROSS_COMPILE)ld -m elf_arm +CPP = $(CC) -E +OBJCOPY = $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S +ARCHCC := $(word 1,$(CC)) +GCCLIB := `$(ARCHCC) $(CFLAGS_PROC) --print-libgcc-file-name` +GCCARCH := -B/usr/src/bin/arm/arm-linuxelf- +HOSTCFLAGS := $(CFLAGS:-fomit-frame-pointer=) +ifeq ($(CONFIG_FRAME_POINTER),y) +CFLAGS := $(CFLAGS:-fomit-frame-pointer=) +endif +CFLAGS := $(CFLAGS_PROC) $(CFLAGS) -pipe +ASFLAGS := $(ASFLAGS_PROC) $(ASFLAGS) -D__ASSEMBLY__ +LINKFLAGS = -T $(TOPDIR)/arch/arm/vmlinux.lds -e stext -Ttext $(TEXTADDR) +ZLINKFLAGS = -Ttext $(ZTEXTADDR) + +SUBDIRS := $(SUBDIRS:drivers=) arch/arm/lib arch/arm/kernel arch/arm/mm arch/arm/drivers +CORE_FILES := arch/arm/kernel/kernel.o arch/arm/mm/mm.o $(CORE_FILES) +LIBS := arch/arm/lib/lib.a $(LIBS) $(GCCLIB) + +DRIVERS := arch/arm/drivers/block/block.a \ + arch/arm/drivers/char/char.a \ + drivers/misc/misc.a \ + arch/arm/drivers/net/net.a + +ifeq ($(CONFIG_SCSI),y) +DRIVERS := $(DRIVERS) arch/arm/drivers/scsi/scsi.a +endif + +ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR),) +DRIVERS := $(DRIVERS) drivers/cdrom/cdrom.a +endif + +ifeq ($(CONFIG_SOUND),y) +DRIVERS := $(DRIVERS) arch/arm/drivers/sound/sound.a +endif + +symlinks:: + $(RM) include/asm-arm/arch include/asm-arm/proc + (cd include/asm-arm; ln -sf arch-$(MACHINE) arch; ln -sf proc-$(PROCESSOR) proc) + +mrproper:: + rm -f include/asm-arm/arch include/asm-arm/proc + @$(MAKE) -C arch/$(ARCH)/drivers mrproper + +arch/arm/kernel: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/arm/kernel + +arch/arm/mm: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/arm/mm + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +zImage: vmlinux + @$(MAKEBOOT) zImage + +zinstall: vmlinux + @$(MAKEBOOT) zinstall + +Image: vmlinux + @$(MAKEBOOT) Image + +install: vmlinux + @$(MAKEBOOT) install + +# My testing targets (that short circuit a few dependencies) +# +zImg:; @$(MAKEBOOT) zImage +Img:; @$(MAKEBOOT) Image +i:; @$(MAKEBOOT) install +zi:; @$(MAKEBOOT) zinstall + +archclean: + @$(MAKEBOOT) clean + @$(MAKE) -C arch/arm/lib clean + +archdep: + @$(MAKEBOOT) dep +sed -e /^MACHINE..*=/s,= .*,= rpc,;/^PROCESSOR..*=/s,= .*,= armv, linux/arch/arm/Makefile.normal diff -ur --new-file old/linux/arch/arm/boot/Makefile new/linux/arch/arm/boot/Makefile --- old/linux/arch/arm/boot/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/boot/Makefile Wed Jan 21 01:39:41 1998 @@ -0,0 +1,35 @@ +# +# arch/arm/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) 1995, 1996 Russell King +# + +SYSTEM =$(TOPDIR)/vmlinux + +Image: $(CONFIGURE) $(SYSTEM) + $(OBJCOPY) $(SYSTEM) $@ + +zImage: $(CONFIGURE) compressed/vmlinux + $(OBJCOPY) compressed/vmlinux $@ + +compressed/vmlinux: $(TOPDIR)/vmlinux dep + @$(MAKE) -C compressed vmlinux + +install: $(CONFIGURE) Image + sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) Image $(TOPDIR)/System.map "$(INSTALL_PATH)" + +zinstall: $(CONFIGURE) zImage + sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)" + +tools/build: tools/build.c + $(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include + +clean: + rm -f Image zImage tools/build + @$(MAKE) -C compressed clean + +dep: diff -ur --new-file old/linux/arch/arm/boot/compressed/Makefile new/linux/arch/arm/boot/compressed/Makefile --- old/linux/arch/arm/boot/compressed/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/boot/compressed/Makefile Wed Jan 21 01:39:41 1998 @@ -0,0 +1,33 @@ +# +# linux/arch/arm/boot/compressed/Makefile +# +# create a compressed vmlinuz image from the original vmlinux +# +# With this config, max compressed image size = 640k +# Uncompressed image size = 1.3M (text+data) + +SYSTEM =$(TOPDIR)/vmlinux +HEAD =$(COMPRESSED_HEAD) +OBJS =$(HEAD) misc.o $(COMPRESSED_EXTRA) +CFLAGS =-O2 -DSTDC_HEADERS $(CFLAGS_PROC) +ARFLAGS =rc + +all: vmlinux + +vmlinux: piggy.o $(OBJS) + $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJS) piggy.o + +$(HEAD): $(HEAD:.o=.S) + $(CC) -traditional -DLOADADDR=$(ZRELADDR) -c $(HEAD:.o=.S) + +piggy.o: $(SYSTEM) + tmppiggy=_tmp_$$$$piggy; \ + rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \ + $(OBJCOPY) $(SYSTEM) $$tmppiggy; \ + gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ + echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ + $(LD) -m elf_arm -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-arm -T $$tmppiggy.lnk; \ + rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; + +clean:; rm -f vmlinux core + diff -ur --new-file old/linux/arch/arm/boot/compressed/Makefile.debug new/linux/arch/arm/boot/compressed/Makefile.debug --- old/linux/arch/arm/boot/compressed/Makefile.debug Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/boot/compressed/Makefile.debug Wed Jan 21 01:39:41 1998 @@ -0,0 +1,16 @@ +# +# linux/arch/arm/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +COMPRESSED_EXTRA=../../lib/ll_char_wr.o +OBJECTS=misc-debug.o $(COMPRESSED_EXTRA) + +CFLAGS=-D__KERNEL__ -O2 -DSTDC_HEADERS -DSTANDALONE_DEBUG -Wall -I../../../../include -c + +test-gzip: piggy.o $(OBJECTS) + $(CC) -o $@ $(OBJECTS) piggy.o + +misc-debug.o: misc.c + $(CC) $(CFLAGS) -o $@ misc.c diff -ur --new-file old/linux/arch/arm/boot/compressed/head-nexuspci.S new/linux/arch/arm/boot/compressed/head-nexuspci.S --- old/linux/arch/arm/boot/compressed/head-nexuspci.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/boot/compressed/head-nexuspci.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,95 @@ +/* + * linux/arch/arm/boot/compressed/head-nexuspci.S + * + * Copyright (C) 1996 Philip Blundell + */ + +#define ARM_CP p15 +#define ARM610_REG_CONTROL cr1 +#define ARM_REG_ZERO cr0 + + .text + +start: b skip1 + b go_uncompress + b go_uncompress + b go_uncompress + b go_uncompress + b go_uncompress + b go_uncompress + b go_uncompress + b go_uncompress + b go_uncompress +skip1: mov sp, #0x40000000 + add sp, sp, #0x200000 + mov r2, #0x20000000 + mov r1, #0x1a + str r1, [r2] + + MOV r0, #0x30 + MCR ARM_CP, 0, r0, ARM610_REG_CONTROL, ARM_REG_ZERO + + mov r2, #0x10000000 + + mov r1, #42 + strb r1, [r2, #8] + + mov r1, #48 + strb r1, [r2, #8] + + mov r1, #16 + strb r1, [r2, #8] + + mov r1, #0x93 + strb r1, [r2, #0] + mov r1, #0x17 + strb r1, [r2, #0] + + mov r1, #0xbb + strb r1, [r2, #0x4] + + mov r1, #0x78 + strb r1, [r2, #0x10] + + mov r1, #160 + strb r1, [r2, #0x8] + + mov r1, #5 + strb r1, [r2, #0x8] + + mov r0, #0x50 + bl _ll_write_char + + mov r4, #0x40000000 + mov r1, #0x00200000 + add r4, r4, r1 +copylp: + ldr r3, [r1] + str r3, [r4, r1] + subs r1, r1, #4 + bne copylp + + add pc, r4, #0x28 + + +/* + * Uncompress the kernel + */ +go_uncompress: + mov r0, #0x40000000 + add r0, r0, #0x300000 + bl _decompress_kernel + + mov r0, #0x40000000 + add r1, r0, #0x300000 + mov r2, #0x100000 + +clp2: ldr r3, [r1, r2] + str r3, [r0, r2] + subs r2, r2, #4 + bne clp2 + + mov r2, #0x40000000 + mov r0, #0 + mov r1, #3 + add pc, r2, #0x20 @ call via EXEC entry diff -ur --new-file old/linux/arch/arm/boot/compressed/head.S new/linux/arch/arm/boot/compressed/head.S --- old/linux/arch/arm/boot/compressed/head.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/boot/compressed/head.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,124 @@ +/* + * linux/arch/arm/boot/compressed/head.S + * + * Copyright (C) 1996,1997,1998 Russell King + */ +#include + + .text +/* + * sort out different calling conventions + */ + .align + .globl _start +_start: +start: mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + mov r0, r0 + teq r0, #0 + beq 2f + mov r4, #0x02000000 + add r4, r4, #0x7C000 + mov r3, #0x4000 + sub r3, r3, #4 +1: ldmia r0!, {r5 - r12} + stmia r4!, {r5 - r12} + subs r3, r3, #32 + bpl 1b +2: adr r2, LC0 + ldmia r2, {r2, r3, r4, r5, r6, sp} + add r2, r2, #3 + add r3, r3, #3 + add sp, sp, #3 + bic r2, r2, #3 + bic r3, r3, #3 + bic sp, sp, #3 + adr r7, start + sub r6, r7, r6 +/* + * Relocate pointers + */ + add r2, r2, r6 + add r3, r3, r6 + add r5, r5, r6 + add sp, sp, r6 +/* + * Clear zero-init + */ + mov r6, #0 +1: str r6, [r2], #4 + cmp r2, r3 + blt 1b + str r1, [r5] @ save architecture +/* + * Uncompress the kernel + */ + mov r1, #0x8000 + add r2, r2, r1, lsl #1 @ Add 64k for malloc + sub r1, r1, #1 + add r2, r2, r1 + bic r5, r2, r1 @ decompress kernel to after end of the compressed + mov r0, r5 + bl SYMBOL_NAME(decompress_kernel) + add r0, r0, #7 + bic r2, r0, #7 +/* + * Now move the kernel to the correct location (r5 -> r4, len r0) + */ + mov r0, r4 @ r0 = start of real kernel + mov r1, r5 @ r1 = start of kernel image + add r3, r5, r2 @ r3 = end of kernel + adr r4, movecode + adr r5, movecodeend +1: ldmia r4!, {r6 - r12, lr} + stmia r3!, {r6 - r12, lr} + cmp r4, r5 + blt 1b + mrc p15, 0, r5, c0, c0 + eor r5, r5, #0x44 << 24 + eor r5, r5, #0x01 << 16 + eor r5, r5, #0xa1 << 8 + movs r5, r5, lsr #4 + mov r5, #0 + mcreq p15, 0, r5, c7, c5, 0 @ flush I cache + ldr r5, LC0 + 12 @ get architecture + ldr r5, [r5] + add pc, r1, r2 @ Call move code + +/* + * r0 = length, r1 = to, r2 = from + */ +movecode: add r3, r1, r2 + mov r4, r0 +1: ldmia r1!, {r6 - r12, lr} + stmia r0!, {r6 - r12, lr} + cmp r1, r3 + blt 1b + mrc p15, 0, r0, c0, c0 + eor r0, r0, #0x44 << 24 + eor r0, r0, #0x01 << 16 + eor r0, r0, #0xa1 << 8 + movs r0, r0, lsr #4 + mov r0, #0 + mcreq p15, 0, r0, c7, c5, 0 @ flush I cache + mov r1, r5 @ call kernel correctly + mov pc, r4 @ call via EXEC entry +movecodeend: + +LC0: .word SYMBOL_NAME(_edata) + .word SYMBOL_NAME(_end) + .word LOADADDR + .word SYMBOL_NAME(architecture) + .word start + .word SYMBOL_NAME(user_stack)+4096 + .align + + .bss +SYMBOL_NAME(architecture): + .space 4 + .align diff -ur --new-file old/linux/arch/arm/boot/compressed/misc.c new/linux/arch/arm/boot/compressed/misc.c --- old/linux/arch/arm/boot/compressed/misc.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/boot/compressed/misc.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,308 @@ +/* + * misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * + * Modified for ARM Linux by Russell King + */ + +#include +#include +#include + +#ifdef STANDALONE_DEBUG +#define puts printf +#endif + +#define __ptr_t void * + +/* + * Optimised C version of memzero for the ARM. + */ +extern __inline__ __ptr_t __memzero (__ptr_t s, size_t n) +{ + union { void *vp; unsigned long *ulp; unsigned char *ucp; } u; + int i; + + u.vp = s; + + for (i = n >> 5; i > 0; i--) { + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + } + + if (n & 1 << 4) { + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + } + + if (n & 1 << 3) { + *u.ulp++ = 0; + *u.ulp++ = 0; + } + + if (n & 1 << 2) + *u.ulp++ = 0; + + if (n & 1 << 1) { + *u.ucp++ = 0; + *u.ucp++ = 0; + } + + if (n & 1) + *u.ucp++ = 0; + return s; +} + +#define memzero(s,n) __memzero(s,n) + +extern __inline__ __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src, + size_t __n) +{ + int i = 0; + unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src; + + for (i = __n >> 3; i > 0; i--) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + + if (__n & 1 << 2) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + + if (__n & 1 << 1) { + *d++ = *s++; + *d++ = *s++; + } + + if (__n & 1) + *d++ = *s++; + + return __dest; +} + +/* + * gzip delarations + */ +#define OF(args) args +#define STATIC static + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize; /* valid bytes in inbuf */ +static unsigned inptr; /* index of next byte to be processed in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern char input_data[]; +extern int input_len; + +static uch *output_data; +static ulg output_ptr; +static ulg bytes_out = 0; + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +static void puts(const char *); + +extern int end; +static ulg free_mem_ptr; +static ulg free_mem_ptr_end; + +#define HEAP_SIZE 0x2000 + +#include "../../../../lib/inflate.c" + +#ifndef STANDALONE_DEBUG +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + if (free_mem_ptr <= 0) error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_ptr_end) + error("Out of memory"); + return p; +} + +static void free(void *where) +{ /* gzip_mark & gzip_release do the free */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} +#else +static void gzip_mark(void **ptr) +{ +} + +static void gzip_release(void **ptr) +{ +} +#endif + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +int fill_inbuf() +{ + if (insize != 0) + error("ran out of input data\n"); + + inbuf = input_data; + insize = input_len; + inptr = 1; + return inbuf[0]; +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +void flush_window() +{ + ulg c = crc; + unsigned n; + uch *in, *out, ch; + + in = window; + out = &output_data[output_ptr]; + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + int ptr; + + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +#define STACK_SIZE (4096) + +ulg user_stack [STACK_SIZE]; + +#ifndef STANDALONE_DEBUG + +ulg decompress_kernel(ulg output_start) +{ + free_mem_ptr = (ulg)&end; + free_mem_ptr_end = output_start; + + proc_decomp_setup (); + arch_decomp_setup (); + + output_data = (uch *)output_start; /* Points to kernel start */ + + makecrc(); + puts("Uncompressing Linux..."); + gunzip(); + puts("done.\nNow booting the kernel\n"); + return output_ptr; +} +#else + +char output_buffer[1500*1024]; + +int main() +{ + output_data = output_buffer; + + makecrc(); + puts("Uncompressing Linux..."); + gunzip(); + puts("done.\n"); + return 0; +} +#endif + diff -ur --new-file old/linux/arch/arm/boot/install.sh new/linux/arch/arm/boot/install.sh --- old/linux/arch/arm/boot/install.sh Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/boot/install.sh Wed Jan 21 01:39:41 1998 @@ -0,0 +1,61 @@ +#!/bin/sh +# +# arch/arm/boot/install.sh +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# Copyright (C) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# Adapted from code in arch/i386/boot/install.sh by Russell King +# +# "make install" script for arm architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +# User may have a custom install script + +if [ -x /sbin/installkernel ]; then + exec /sbin/installkernel "$@" +fi + +if [ "$2" = "zImage" ]; then +# Compressed install + echo "Installing compressed kernel" + if [ -f $4/vmlinuz-$1 ]; then + mv $4/vmlinuz-$1 $4/vmlinuz.old + fi + + if [ -f $4/System.map-$1 ]; then + mv $4/System.map-$1 $4/System.old + fi + + cat $2 > $4/vmlinuz-$1 + cp $3 $4/System.map-$1 +else +# Normal install + echo "Installing normal kernel" + if [ -f $4/vmlinux-$1 ]; then + mv $4/vmlinux-$1 $4/vmlinux.old + fi + + if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old + fi + + cat $2 > $4/vmlinux-$1 + cp $3 $4/System.map +fi + +if [ -x /sbin/loadmap ]; then + /sbin/loadmap --rdev /dev/ima +else + echo "You have to install it yourself" +fi diff -ur --new-file old/linux/arch/arm/boot/tools/build.c new/linux/arch/arm/boot/tools/build.c --- old/linux/arch/arm/boot/tools/build.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/boot/tools/build.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long u32; + +void die(const char * str, ...) +{ + va_list args; + va_start(args, str); + vfprintf(stderr, str, args); + fputc('\n', stderr); + exit (1); +} + +int main(int argc, char **argv) +{ + void *data; + struct exec ex; + FILE *f; + int totlen; + + if (argc < 2) { + fprintf(stderr, "Usage: build kernel-name\n"); + exit(1); + } + + f = fopen(argv[1], "rb"); + if (!f) + die("Unable to open `%s': %m", argv[1]); + + fread(&ex, 1, sizeof(ex), f); + + if(N_MAGIC(ex) == ZMAGIC) { + fseek(f, 4096, SEEK_SET); + totlen = ex.a_text + ex.a_data; + } else + if(N_MAGIC(ex) == QMAGIC) { + unsigned long my_header; + + fseek(f, 4, SEEK_SET); + + my_header = 0xea000006; + + fwrite(&my_header, 4, 1, stdout); + + totlen = ex.a_text + ex.a_data - 4; + } else { + fprintf(stderr, "Unacceptable a.out header on kernel\n"); + fclose(f); + exit(1); + } + + fprintf(stderr, "Kernel is %dk (%dk text, %dk data, %dk bss)\n", + (ex.a_text + ex.a_data + ex.a_bss)/1024, + ex.a_text/1024, ex.a_data/1024, ex.a_bss/1024); + + data = malloc(totlen); + fread(data, 1, totlen, f); + fwrite(data, 1, totlen, stdout); + + free(data); + fclose(f); + fflush(stdout); + return 0; +} diff -ur --new-file old/linux/arch/arm/config.in new/linux/arch/arm/config.in --- old/linux/arch/arm/config.in Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/config.in Thu Mar 12 00:13:49 1998 @@ -0,0 +1,145 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +mainmenu_name "Linux Kernel Configuration" + +define_bool CONFIG_ARM y + +mainmenu_option next_comment +comment 'Code maturity level options' +bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +endmenu + +mainmenu_option next_comment +comment 'Loadable module support' +bool 'Enable loadable module support' CONFIG_MODULES +if [ "$CONFIG_MODULES" = "y" ]; then + bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS + bool 'Kernel module loader' CONFIG_KMOD +fi +endmenu + +mainmenu_option next_comment +comment 'General setup' +choice 'ARM system type' \ + "Archimedes CONFIG_ARCH_ARC \ + A5000 CONFIG_ARCH_A5K \ + RiscPC CONFIG_ARCH_RPC \ + EBSA-110 CONFIG_ARCH_EBSA110 \ + NexusPCI CONFIG_ARCH_NEXUSPCI" RiscPC +if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" -o "$CONFIG_ARCH_RPC" = "y" ]; then + define_bool CONFIG_ARCH_ACORN y +else + define_bool CONFIG_ARCH_ACORN n +fi +if [ "$CONFIG_ARCH_NEXUSPCI" = "y" ]; then + define_bool CONFIG_PCI y +else + define_bool CONFIG_PCI n +fi +if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_EBSA110" = "y" ]; then + define_bool CONFIG_CPU_SA110 y +else + if [ "$CONFIG_ARCH_A5K" = "y" ]; then + define_bool CONFIG_CPU_ARM3 y + else + choice 'ARM cpu type' \ + "ARM2 CONFIG_CPU_ARM2 \ + ARM3 CONFIG_CPU_ARM3 \ + ARM6/7 CONFIG_CPU_ARM6 \ + StrongARM CONFIG_CPU_SA110" StrongARM + fi +fi +bool 'Compile kernel with frame pointer (for useful debugging)' CONFIG_FRAME_POINTER +bool 'Use new compilation options (for GCC 2.8)' CONFIG_BINUTILS_NEW +bool 'Debug kernel errors' CONFIG_DEBUG_ERRORS +bool 'Networking support' CONFIG_NET +bool 'System V IPC' CONFIG_SYSVIPC +bool 'Sysctl support' CONFIG_SYSCTL +tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +# tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA + define_bool CONFIG_BINFMT_JAVA n +fi +tristate 'Parallel port support' CONFIG_PARPORT +if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT +fi +endmenu + +source arch/arm/drivers/block/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in +fi + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support?' CONFIG_SCSI + +if [ "$CONFIG_SCSI" != "n" ]; then + source arch/arm/drivers/scsi/Config.in +fi +endmenu + +if [ "$CONFIG_NET" = "y" ]; then + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support?' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source arch/arm/drivers/net/Config.in + fi + endmenu +fi + +# mainmenu_option next_comment +# comment 'ISDN subsystem' +# +# tristate 'ISDN support' CONFIG_ISDN +# if [ "$CONFIG_ISDN" != "n" ]; then +# source drivers/isdn/Config.in +# fi +# endmenu + +# Conditionally compile in the Uniform CD-ROM driver +if [ "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_BLK_DEV_SR" = "y" ]; then + define_bool CONFIG_CDROM y +else + if [ "$CONFIG_BLK_DEV_IDECD" = "m" -o "$CONFIG_BLK_DEV_SR" = "m" ]; then + define_bool CONFIG_CDROM m + else + define_bool CONFIG_CDROM n + fi +fi + +source fs/Config.in + +source fs/nls/Config.in + +source arch/arm/drivers/char/Config.in + +if [ "$CONFIG_ARCH_ACORN" = "y" ]; then + mainmenu_option next_comment + comment 'Sound' + + tristate 'Sound support' CONFIG_SOUND + if [ "$CONFIG_SOUND" != "n" ]; then + source arch/arm/drivers/sound/Config.in + fi + endmenu +fi + +mainmenu_option next_comment +comment 'Kernel hacking' + +#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC +bool 'Kernel profiling support' CONFIG_PROFILE +if [ "$CONFIG_PROFILE" = "y" ]; then + int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 +fi +bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +endmenu diff -ur --new-file old/linux/arch/arm/defconfig new/linux/arch/arm/defconfig --- old/linux/arch/arm/defconfig Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/defconfig Thu Mar 12 00:13:49 1998 @@ -0,0 +1,264 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# +# General setup +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +CONFIG_ARCH_RPC=y +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_NEXUSPCI is not set +CONFIG_ARCH_ACORN=y +# CONFIG_PCI is not set +# CONFIG_CPU_ARM2 is not set +# CONFIG_CPU_ARM3 is not set +# CONFIG_CPU_ARM6 is not set +CONFIG_CPU_SA110=y +CONFIG_FRAME_POINTER=y +# CONFIG_BINUTILS_NEW is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +CONFIG_SYSCTL=y +CONFIG_BINFMT_AOUT=y +CONFIG_BINFMT_ELF=m +# CONFIG_BINFMT_JAVA is not set +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y + +# +# Floppy, IDE, and other block devices +# +CONFIG_BLK_DEV_FD=y +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_IDESCSI is not set +# CONFIG_BLK_DEV_IDE_PCMCIA is not set +CONFIG_BLK_DEV_IDE_CARDS=y +CONFIG_BLK_DEV_IDE_ICSIDE=y +# CONFIG_BLK_DEV_IDE_RAPIDE is not set +# CONFIG_BLK_DEV_XD is not set + +# +# Additional Block Devices +# +CONFIG_BLK_DEV_LOOP=m +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_PARIDE_PARPORT=y +# CONFIG_PARIDE is not set +CONFIG_BLK_DEV_PART=y +# CONFIG_BLK_DEV_HD is not set + +# +# Networking options +# +CONFIG_PACKET=m +# 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 +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_IP_ACCT is not set +# CONFIG_IP_MASQUERADE 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 is not set + +# +# (it is safe to leave these untouched) +# +# CONFIG_INET_RARP is not set +CONFIG_IP_NOSR=y +# CONFIG_SKB_LARGE is not set +# CONFIG_IPV6 is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_BRIDGE is not set +# CONFIG_LLC is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_CPU_IS_SLOW is not set +# CONFIG_NET_SCHED is not set + +# +# SCSI support +# +CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_CHR_DEV_SG is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +CONFIG_SCSI_ACORNSCSI_3=m +CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y +CONFIG_SCSI_ACORNSCSI_SYNC=y +CONFIG_SCSI_CUMANA_2=m +CONFIG_SCSI_POWERTECSCSI=m + +# +# The following drives are not fully supported +# +CONFIG_SCSI_CUMANA_1=m +CONFIG_SCSI_ECOSCSI=m +CONFIG_SCSI_OAK1=m +CONFIG_SCSI_PPA=m +CONFIG_SCSI_PPA_HAVE_PEDANTIC=2 + +# +# Network device support +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +CONFIG_PPP=m + +# +# CCP compressors for PPP are only built as modules. +# +# CONFIG_SLIP is not set +CONFIG_ETHER1=m +CONFIG_ETHER3=m +CONFIG_ETHERH=m +CONFIG_CDROM=y + +# +# Filesystems +# +# CONFIG_QUOTA is not set +# CONFIG_MINIX_FS is not set +CONFIG_EXT2_FS=y +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_PROC_FS=y +CONFIG_NFS_FS=y +CONFIG_NFSD=y +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_CODA_FS is not set +# CONFIG_SMB_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_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_ADFS_FS=y +# CONFIG_MAC_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_KOI8_R is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +CONFIG_ATOMWIDE_SERIAL=y +CONFIG_DUALSP_SERIAL=y +CONFIG_MOUSE=y +CONFIG_PRINTER=m +CONFIG_PRINTER_READBACK=y +# CONFIG_UMISC is not set +# CONFIG_WATCHDOG is not set +CONFIG_RPCMOUSE=y + +# +# Sound +# +# CONFIG_SOUND is not set +# CONFIG_VIDC is not set +# CONFIG_AUDIO is not set +# DSP_BUFFSIZE is not set + +# +# Kernel hacking +# +# CONFIG_PROFILE is not set +CONFIG_MAGIC_SYSRQ=y diff -ur --new-file old/linux/arch/arm/kernel/Makefile new/linux/arch/arm/kernel/Makefile --- old/linux/arch/arm/kernel/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/Makefile Wed Jan 21 01:39:41 1998 @@ -0,0 +1,47 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +HEAD_OBJ = head-$(PROCESSOR).o +ENTRY_OBJ = entry-$(PROCESSOR).o + +O_TARGET := kernel.o +O_OBJS := $(ENTRY_OBJ) ioport.o irq.o process.o ptrace.o signal.o sys_arm.o time.o traps.o + +all: kernel.o $(HEAD_OBJ) init_task.o + +ifeq ($(CONFIG_MODULES),y) +OX_OBJS = armksyms.o +else +O_OBJS += armksyms.o +endif + +ifdef CONFIG_ARCH_ACORN + O_OBJS += setup.o ecard.o iic.o dma.o + ifdef CONFIG_ARCH_ARC + O_OBJS += oldlatches.o + endif +endif + +ifeq ($(MACHINE),ebsa110) + O_OBJS += setup-ebsa110.o dma.o +endif + +ifeq ($(MACHINE),nexuspci) + O_OBJS += setup-ebsa110.o +endif + +$(HEAD_OBJ): $(HEAD_OBJ:.o=.S) + $(CC) -D__ASSEMBLY__ -traditional -c $(HEAD_OBJ:.o=.S) -o $@ + +include $(TOPDIR)/Rules.make + +$(ENTRY_OBJ:.o=.S): ../lib/constants.h + +.PHONY: ../lib/constants.h + +../lib/constants.h: + $(MAKE) -C ../lib constants.h diff -ur --new-file old/linux/arch/arm/kernel/armksyms.c new/linux/arch/arm/kernel/armksyms.c --- old/linux/arch/arm/kernel/armksyms.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/armksyms.c Wed Mar 18 06:15:40 1998 @@ -0,0 +1,183 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern void dump_thread(struct pt_regs *, struct user *); +extern int dump_fpu(struct pt_regs *, struct user_fp_struct *); + +/* + * libgcc functions - functions that are used internally by the + * compiler... (prototypes are not correct though, but that + * doesn't really matter since they're not versioned). + */ +extern void __gcc_bcmp(void); +extern void __ashldi3(void); +extern void __ashrdi3(void); +extern void __cmpdi2(void); +extern void __divdi3(void); +extern void __divsi3(void); +extern void __lshrdi3(void); +extern void __moddi3(void); +extern void __modsi3(void); +extern void __muldi3(void); +extern void __negdi2(void); +extern void __ucmpdi2(void); +extern void __udivdi3(void); +extern void __udivmoddi4(void); +extern void __udivsi3(void); +extern void __umoddi3(void); +extern void __umodsi3(void); + +extern void inswb(unsigned int port, void *to, int len); +extern void outswb(unsigned int port, const void *to, int len); + +/* + * floating point math emulator support. + * These will not change. If they do, then a new version + * of the emulator will have to be compiled... + * fp_current is never actually dereferenced - it is just + * used as a pointer to pass back for send_sig(). + */ +extern void (*fp_save)(unsigned char *); +extern void (*fp_restore)(unsigned char *); +extern void fp_setup(void); +extern void fpreturn(void); +extern void fpundefinstr(void); +extern void fp_enter(void); +extern void fp_printk(void); +extern struct task_struct *fp_current; +extern void fp_send_sig(int); + +/* platform dependent support */ +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(udelay); +EXPORT_SYMBOL(dma_str); +EXPORT_SYMBOL(xchg_str); + +/* expansion card support */ +#ifdef CONFIG_ARCH_ACORN +EXPORT_SYMBOL(ecard_startfind); +EXPORT_SYMBOL(ecard_find); +EXPORT_SYMBOL(ecard_readchunk); +EXPORT_SYMBOL(ecard_address); +#endif + +/* processor dependencies */ +EXPORT_SYMBOL(processor); + +/* io */ +EXPORT_SYMBOL(outswb); +EXPORT_SYMBOL(outsw); +EXPORT_SYMBOL(inswb); +EXPORT_SYMBOL(insw); + +#ifdef CONFIG_ARCH_RPC +EXPORT_SYMBOL(drambank); +#endif + +/* dma */ +EXPORT_SYMBOL(enable_dma); +EXPORT_SYMBOL(set_dma_mode); +EXPORT_SYMBOL(set_dma_addr); +EXPORT_SYMBOL(set_dma_count); +EXPORT_SYMBOL(get_dma_residue); + +/* + * floating point math emulator support. + * These symbols will never change their calling convention... + */ +EXPORT_SYMBOL_NOVERS(fpreturn); +EXPORT_SYMBOL_NOVERS(fpundefinstr); +EXPORT_SYMBOL_NOVERS(fp_enter); +EXPORT_SYMBOL_NOVERS(fp_save); +EXPORT_SYMBOL_NOVERS(fp_restore); +EXPORT_SYMBOL_NOVERS(fp_setup); + +const char __kstrtab_fp_printk[] __attribute__((section(".kstrtab"))) = __MODULE_STRING(fp_printk); +const struct module_symbol __ksymtab_fp_printk __attribute__((section("__ksymtab"))) = +{ (unsigned long)&printk, __kstrtab_fp_printk }; + +const char __kstrtab_fp_send_sig[] __attribute__((section(".kstrtab"))) = __MODULE_STRING(fp_send_sig); +const struct module_symbol __ksymtab_fp_send_sig __attribute__((section("__ksymtab"))) = +{ (unsigned long)&send_sig, __kstrtab_fp_send_sig }; + +//EXPORT_SYMBOL_NOVERS(fp_current); + + /* + * string / mem functions + */ +EXPORT_SYMBOL_NOVERS(strcpy); +EXPORT_SYMBOL_NOVERS(strncpy); +EXPORT_SYMBOL_NOVERS(strcat); +EXPORT_SYMBOL_NOVERS(strncat); +EXPORT_SYMBOL_NOVERS(strcmp); +EXPORT_SYMBOL_NOVERS(strncmp); +EXPORT_SYMBOL_NOVERS(strchr); +EXPORT_SYMBOL_NOVERS(strlen); +EXPORT_SYMBOL_NOVERS(strnlen); +EXPORT_SYMBOL_NOVERS(strspn); +EXPORT_SYMBOL_NOVERS(strpbrk); +EXPORT_SYMBOL_NOVERS(strtok); +EXPORT_SYMBOL_NOVERS(strrchr); +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL_NOVERS(memzero); + + /* user mem (segment) */ +#if defined(CONFIG_CPU_ARM6) || defined(CONFIG_CPU_SA110) +EXPORT_SYMBOL(__arch_copy_from_user); +EXPORT_SYMBOL(__arch_copy_to_user); +EXPORT_SYMBOL(__arch_clear_user); +EXPORT_SYMBOL(__arch_strlen_user); +#elif defined(CONFIG_CPU_ARM2) || defined(CONFIG_CPU_ARM3) +EXPORT_SYMBOL(uaccess_kernel); +EXPORT_SYMBOL(uaccess_user); +#endif + + /* gcc lib functions */ +EXPORT_SYMBOL_NOVERS(__gcc_bcmp); +EXPORT_SYMBOL_NOVERS(__ashldi3); +EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__cmpdi2); +EXPORT_SYMBOL_NOVERS(__divdi3); +EXPORT_SYMBOL_NOVERS(__divsi3); +EXPORT_SYMBOL_NOVERS(__lshrdi3); +EXPORT_SYMBOL_NOVERS(__moddi3); +EXPORT_SYMBOL_NOVERS(__modsi3); +EXPORT_SYMBOL_NOVERS(__muldi3); +EXPORT_SYMBOL_NOVERS(__negdi2); +EXPORT_SYMBOL_NOVERS(__ucmpdi2); +EXPORT_SYMBOL_NOVERS(__udivdi3); +EXPORT_SYMBOL_NOVERS(__udivmoddi4); +EXPORT_SYMBOL_NOVERS(__udivsi3); +EXPORT_SYMBOL_NOVERS(__umoddi3); +EXPORT_SYMBOL_NOVERS(__umodsi3); + + /* bitops */ +EXPORT_SYMBOL(set_bit); +EXPORT_SYMBOL(test_and_set_bit); +EXPORT_SYMBOL(clear_bit); +EXPORT_SYMBOL(test_and_clear_bit); +EXPORT_SYMBOL(change_bit); +EXPORT_SYMBOL(test_and_change_bit); +EXPORT_SYMBOL(find_first_zero_bit); +EXPORT_SYMBOL(find_next_zero_bit); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff -ur --new-file old/linux/arch/arm/kernel/calls.S new/linux/arch/arm/kernel/calls.S --- old/linux/arch/arm/kernel/calls.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/calls.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,194 @@ +/* + * linux/arch/arm/lib/calls.h + * + * Copyright (C) 1995, 1996 Russell King + */ +#ifndef NR_SYSCALLS +#define NR_syscalls 256 +#define NR_SYSCALLS 182 +#else + +/* 0 */ .long SYMBOL_NAME(sys_setup) + .long SYMBOL_NAME(sys_exit) + .long SYMBOL_NAME(sys_fork_wrapper) + .long SYMBOL_NAME(sys_read) + .long SYMBOL_NAME(sys_write) +/* 5 */ .long SYMBOL_NAME(sys_open) + .long SYMBOL_NAME(sys_close) + .long SYMBOL_NAME(sys_waitpid) + .long SYMBOL_NAME(sys_creat) + .long SYMBOL_NAME(sys_link) +/* 10 */ .long SYMBOL_NAME(sys_unlink) + .long SYMBOL_NAME(sys_execve_wrapper) + .long SYMBOL_NAME(sys_chdir) + .long SYMBOL_NAME(sys_time) + .long SYMBOL_NAME(sys_mknod) +/* 15 */ .long SYMBOL_NAME(sys_chmod) + .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_break */ + .long SYMBOL_NAME(sys_stat) + .long SYMBOL_NAME(sys_lseek) +/* 20 */ .long SYMBOL_NAME(sys_getpid) + .long SYMBOL_NAME(sys_mount_wrapper) + .long SYMBOL_NAME(sys_umount) + .long SYMBOL_NAME(sys_setuid) + .long SYMBOL_NAME(sys_getuid) +/* 25 */ .long SYMBOL_NAME(sys_stime) + .long SYMBOL_NAME(sys_ptrace) + .long SYMBOL_NAME(sys_alarm) + .long SYMBOL_NAME(sys_fstat) + .long SYMBOL_NAME(sys_pause) +/* 30 */ .long SYMBOL_NAME(sys_utime) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_stty */ + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_getty */ + .long SYMBOL_NAME(sys_access) + .long SYMBOL_NAME(sys_nice) +/* 35 */ .long SYMBOL_NAME(sys_ni_syscall) /* was sys_ftime */ + .long SYMBOL_NAME(sys_sync) + .long SYMBOL_NAME(sys_kill) + .long SYMBOL_NAME(sys_rename) + .long SYMBOL_NAME(sys_mkdir) +/* 40 */ .long SYMBOL_NAME(sys_rmdir) + .long SYMBOL_NAME(sys_dup) + .long SYMBOL_NAME(sys_pipe) + .long SYMBOL_NAME(sys_times) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_prof */ +/* 45 */ .long SYMBOL_NAME(sys_brk) + .long SYMBOL_NAME(sys_setgid) + .long SYMBOL_NAME(sys_getgid) + .long SYMBOL_NAME(sys_signal) + .long SYMBOL_NAME(sys_geteuid) +/* 50 */ .long SYMBOL_NAME(sys_getegid) + .long SYMBOL_NAME(sys_acct) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_phys */ + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_lock */ + .long SYMBOL_NAME(sys_ioctl) +/* 55 */ .long SYMBOL_NAME(sys_fcntl) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_mpx */ + .long SYMBOL_NAME(sys_setpgid) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_ulimit */ + .long SYMBOL_NAME(sys_olduname) +/* 60 */ .long SYMBOL_NAME(sys_umask) + .long SYMBOL_NAME(sys_chroot) + .long SYMBOL_NAME(sys_ustat) + .long SYMBOL_NAME(sys_dup2) + .long SYMBOL_NAME(sys_getppid) +/* 65 */ .long SYMBOL_NAME(sys_getpgrp) + .long SYMBOL_NAME(sys_setsid) + .long SYMBOL_NAME(sys_sigaction) + .long SYMBOL_NAME(sys_sgetmask) + .long SYMBOL_NAME(sys_ssetmask) +/* 70 */ .long SYMBOL_NAME(sys_setreuid) + .long SYMBOL_NAME(sys_setregid) + .long SYMBOL_NAME(sys_sigsuspend_wrapper) + .long SYMBOL_NAME(sys_sigpending) + .long SYMBOL_NAME(sys_sethostname) +/* 75 */ .long SYMBOL_NAME(sys_setrlimit) + .long SYMBOL_NAME(sys_getrlimit) + .long SYMBOL_NAME(sys_getrusage) + .long SYMBOL_NAME(sys_gettimeofday) + .long SYMBOL_NAME(sys_settimeofday) +/* 80 */ .long SYMBOL_NAME(sys_getgroups) + .long SYMBOL_NAME(sys_setgroups) + .long SYMBOL_NAME(old_select) + .long SYMBOL_NAME(sys_symlink) + .long SYMBOL_NAME(sys_lstat) +/* 85 */ .long SYMBOL_NAME(sys_readlink) + .long SYMBOL_NAME(sys_uselib) + .long SYMBOL_NAME(sys_swapon) + .long SYMBOL_NAME(sys_reboot) + .long SYMBOL_NAME(old_readdir) +/* 90 */ .long SYMBOL_NAME(old_mmap) + .long SYMBOL_NAME(sys_munmap) + .long SYMBOL_NAME(sys_truncate) + .long SYMBOL_NAME(sys_ftruncate) + .long SYMBOL_NAME(sys_fchmod) +/* 95 */ .long SYMBOL_NAME(sys_fchown) + .long SYMBOL_NAME(sys_getpriority) + .long SYMBOL_NAME(sys_setpriority) + .long SYMBOL_NAME(sys_ni_syscall) /* was sys_profil */ + .long SYMBOL_NAME(sys_statfs) +/* 100 */ .long SYMBOL_NAME(sys_fstatfs) + .long SYMBOL_NAME(sys_ni_syscall) /* .long _sys_ioperm */ + .long SYMBOL_NAME(sys_socketcall) + .long SYMBOL_NAME(sys_syslog) + .long SYMBOL_NAME(sys_setitimer) +/* 105 */ .long SYMBOL_NAME(sys_getitimer) + .long SYMBOL_NAME(sys_newstat) + .long SYMBOL_NAME(sys_newlstat) + .long SYMBOL_NAME(sys_newfstat) + .long SYMBOL_NAME(sys_uname) +/* 110 */ .long SYMBOL_NAME(sys_iopl) + .long SYMBOL_NAME(sys_vhangup) + .long SYMBOL_NAME(sys_idle) + .long SYMBOL_NAME(sys_syscall) /* call a syscall */ + .long SYMBOL_NAME(sys_wait4) +/* 115 */ .long SYMBOL_NAME(sys_swapoff) + .long SYMBOL_NAME(sys_sysinfo) + .long SYMBOL_NAME(sys_ipc) + .long SYMBOL_NAME(sys_fsync) + .long SYMBOL_NAME(sys_sigreturn_wrapper) + .long SYMBOL_NAME(sys_clone_wapper) + .long SYMBOL_NAME(sys_setdomainname) + .long SYMBOL_NAME(sys_newuname) + .long SYMBOL_NAME(sys_ni_syscall) /* .long SYMBOL_NAME(sys_modify_ldt) */ + .long SYMBOL_NAME(sys_adjtimex) +/* 125 */ .long SYMBOL_NAME(sys_mprotect) + .long SYMBOL_NAME(sys_sigprocmask) + .long SYMBOL_NAME(sys_create_module) + .long SYMBOL_NAME(sys_init_module) + .long SYMBOL_NAME(sys_delete_module) +/* 130 */ .long SYMBOL_NAME(sys_get_kernel_syms) + .long SYMBOL_NAME(sys_quotactl) + .long SYMBOL_NAME(sys_getpgid) + .long SYMBOL_NAME(sys_fchdir) + .long SYMBOL_NAME(sys_bdflush) +/* 135 */ .long SYMBOL_NAME(sys_sysfs) + .long SYMBOL_NAME(sys_personality) + .long SYMBOL_NAME(sys_ni_syscall) /* .long _sys_afs_syscall */ + .long SYMBOL_NAME(sys_setfsuid) + .long SYMBOL_NAME(sys_setfsgid) +/* 140 */ .long SYMBOL_NAME(sys_llseek_wrapper) + .long SYMBOL_NAME(sys_getdents) + .long SYMBOL_NAME(sys_select) + .long SYMBOL_NAME(sys_flock) + .long SYMBOL_NAME(sys_msync) +/* 145 */ .long SYMBOL_NAME(sys_readv) + .long SYMBOL_NAME(sys_writev) + .long SYMBOL_NAME(sys_getsid) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) +/* 150 */ .long SYMBOL_NAME(sys_mlock) + .long SYMBOL_NAME(sys_munlock) + .long SYMBOL_NAME(sys_mlockall) + .long SYMBOL_NAME(sys_munlockall) + .long SYMBOL_NAME(sys_sched_setparam) +/* 155 */ .long SYMBOL_NAME(sys_sched_getparam) + .long SYMBOL_NAME(sys_sched_setscheduler) + .long SYMBOL_NAME(sys_sched_getscheduler) + .long SYMBOL_NAME(sys_sched_yield) + .long SYMBOL_NAME(sys_sched_get_priority_max) +/* 160 */ .long SYMBOL_NAME(sys_sched_get_priority_min) + .long SYMBOL_NAME(sys_sched_rr_get_interval) + .long SYMBOL_NAME(sys_nanosleep) + .long SYMBOL_NAME(sys_mremap) + .long SYMBOL_NAME(sys_setresuid) +/* 165 */ .long SYMBOL_NAME(sys_getresuid) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_query_module) + .long SYMBOL_NAME(sys_poll) + .long SYMBOL_NAME(sys_nfsservctl) +/* 170 */ .long SYMBOL_NAME(sys_setresgid) + .long SYMBOL_NAME(sys_getresgid) + .long SYMBOL_NAME(sys_prctl) + .long SYMBOL_NAME(sys_rt_sigreturn_wrapper) + .long SYMBOL_NAME(sys_rt_sigaction) +/* 175 */ .long SYMBOL_NAME(sys_rt_sigprocmask) + .long SYMBOL_NAME(sys_rt_sigpending) + .long SYMBOL_NAME(sys_rt_sigtimedwait) + .long SYMBOL_NAME(sys_rt_sigqueueinfo) + .long SYMBOL_NAME(sys_rt_sigsuspend_wrapper) +/* 180 */ .long SYMBOL_NAME(sys_pread) + .long SYMBOL_NAME(sys_pwrite) + .space (NR_syscalls - 182) * 4 +#endif diff -ur --new-file old/linux/arch/arm/kernel/dma.c new/linux/arch/arm/kernel/dma.c --- old/linux/arch/arm/kernel/dma.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/dma.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,199 @@ +/* + * linux/arch/arm/kernel/dma.c + * + * Copyright (C) 1995, 1996 Russell King + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#define KERNEL_ARCH_DMA +#include + +static unsigned long dma_address[8]; +static unsigned long dma_count[8]; +static char dma_direction[8] = { -1, -1, -1, -1, -1, -1, -1}; + +#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_RPC) +#define DMA_PCIO +#endif +#if defined(CONFIG_ARCH_ARC) && defined(CONFIG_BLK_DEV_FD) +#define DMA_OLD +#endif + +void enable_dma (unsigned int dmanr) +{ + switch (dmanr) { +#ifdef DMA_PCIO + case 2: { + void *fiqhandler_start; + unsigned int fiqhandler_length; + extern void floppy_fiqsetup (unsigned long len, unsigned long addr, + unsigned long port); + switch (dma_direction[dmanr]) { + case 1: { + extern unsigned char floppy_fiqin_start, floppy_fiqin_end; + fiqhandler_start = &floppy_fiqin_start; + fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start; + break; + } + case 0: { + extern unsigned char floppy_fiqout_start, floppy_fiqout_end; + fiqhandler_start = &floppy_fiqout_start; + fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start; + break; + } + default: + printk ("enable_dma: dma%d not initialised\n", dmanr); + return; + } + memcpy ((void *)0x1c, fiqhandler_start, fiqhandler_length); + flush_page_to_ram(0); + floppy_fiqsetup (dma_count[dmanr], dma_address[dmanr], (int)PCIO_FLOPPYDMABASE); + enable_irq (64); + return; + } +#endif +#ifdef DMA_OLD + case 0: { /* Data DMA */ + switch (dma_direction[dmanr]) { + case 1: /* read */ + { + extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end; + extern void fdc1772_setupdma(unsigned int count,unsigned int addr); + unsigned long flags; +#ifdef DEBUG + printk("enable_dma fdc1772 data read\n"); +#endif + save_flags(flags); + cliIF(); + + memcpy ((void *)0x1c, (void *)&fdc1772_dma_read, + &fdc1772_dma_read_end - &fdc1772_dma_read); + fdc1772_setupdma(dma_count[dmanr],dma_address[dmanr]); /* Sets data pointer up */ + enable_irq (64); + restore_flags(flags); + } + break; + + case 0: /* write */ + { + extern unsigned char fdc1772_dma_write, fdc1772_dma_write_end; + extern void fdc1772_setupdma(unsigned int count,unsigned int addr); + unsigned long flags; + +#ifdef DEBUG + printk("enable_dma fdc1772 data write\n"); +#endif + save_flags(flags); + cliIF(); + memcpy ((void *)0x1c, (void *)&fdc1772_dma_write, + &fdc1772_dma_write_end - &fdc1772_dma_write); + fdc1772_setupdma(dma_count[dmanr],dma_address[dmanr]); /* Sets data pointer up */ + enable_irq (64); + + restore_flags(flags); + } + break; + default: + printk ("enable_dma: dma%d not initialised\n", dmanr); + return; + } + } + break; + + case 1: { /* Command end FIQ - actually just sets a flag */ + /* Need to build a branch at the FIQ address */ + extern void fdc1772_comendhandler(void); + unsigned long flags; + + /*printk("enable_dma fdc1772 command end FIQ\n");*/ + save_flags(flags); + cliIF(); + + *((unsigned int *)0x1c)=0xea000000 | (((unsigned int)fdc1772_comendhandler-(0x1c+8))/4); /* B fdc1772_comendhandler */ + + restore_flags(flags); + } + break; +#endif + case DMA_0: + case DMA_1: + case DMA_2: + case DMA_3: + case DMA_S0: + case DMA_S1: + arch_enable_dma (dmanr - DMA_0); + break; + + default: + printk ("enable_dma: dma %d not supported\n", dmanr); + } +} + +void set_dma_mode (unsigned int dmanr, char mode) +{ + if (dmanr < 8) { + if (mode == DMA_MODE_READ) + dma_direction[dmanr] = 1; + else if (mode == DMA_MODE_WRITE) + dma_direction[dmanr] = 0; + else + printk ("set_dma_mode: dma%d: invalid mode %02X not supported\n", + dmanr, mode); + } else if (dmanr < MAX_DMA_CHANNELS) + arch_set_dma_mode (dmanr - DMA_0, mode); + else + printk ("set_dma_mode: dma %d not supported\n", dmanr); +} + +void set_dma_addr (unsigned int dmanr, unsigned int addr) +{ + if (dmanr < 8) + dma_address[dmanr] = (unsigned long)addr; + else if (dmanr < MAX_DMA_CHANNELS) + arch_set_dma_addr (dmanr - DMA_0, addr); + else + printk ("set_dma_addr: dma %d not supported\n", dmanr); +} + +void set_dma_count (unsigned int dmanr, unsigned int count) +{ + if (dmanr < 8) + dma_count[dmanr] = (unsigned long)count; + else if (dmanr < MAX_DMA_CHANNELS) + arch_set_dma_count (dmanr - DMA_0, count); + else + printk ("set_dma_count: dma %d not supported\n", dmanr); +} + +int get_dma_residue (unsigned int dmanr) +{ + if (dmanr < 8) { + switch (dmanr) { +#if defined(CONFIG_ARCH_A5K) || defined(CONFIG_ARCH_RPC) + case 2: { + extern int floppy_fiqresidual (void); + return floppy_fiqresidual (); + } +#endif +#if defined(CONFIG_ARCH_ARC) && defined(CONFIG_BLK_DEV_FD) + case 0: { + extern unsigned int fdc1772_bytestogo; + return fdc1772_bytestogo; + } +#endif + default: + return -1; + } + } else if (dmanr < MAX_DMA_CHANNELS) + return arch_dma_count (dmanr - DMA_0); + return -1; +} diff -ur --new-file old/linux/arch/arm/kernel/ecard.c new/linux/arch/arm/kernel/ecard.c --- old/linux/arch/arm/kernel/ecard.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/ecard.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,604 @@ +/* + * linux/arch/arm/kernel/ecard.c + * + * Find all installed expansion cards, and handle interrupts from them. + * + * Copyright 1995,1996,1997 Russell King + * + * Created from information from Acorns RiscOS3 PRMs + * + * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether podule slot. + * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. + * 12-Sep-1997 RMK Created new handling of interrupt enables/disables - cards can + * now register their own routine to control interrupts (recommended). + * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled on reset from + * Linux. (Caused cards not to respond under RiscOS without hard reset). + */ + +#define ECARD_C + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ARCH_ARC +#include +#else +#define oldlatch_init() +#endif + +#define BLACKLIST_NAME(m,p,s) { m, p, NULL, s } +#define BLACKLIST_LOADER(m,p,l) { m, p, l, NULL } +#define BLACKLIST_NOLOADER(m,p) { m, p, noloader, blacklisted_str } +#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) + +extern unsigned long atomwide_serial_loader[], oak_scsi_loader[], noloader[]; +static const char blacklisted_str[] = "*loader blacklisted - not 32-bit compliant*"; + +static const struct expcard_blacklist { + unsigned short manufacturer; + unsigned short product; + const loader_t loader; + const char *type; +} blacklist[] = { +/* Cards without names */ + BLACKLIST_NAME(MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1"), + +/* Cards with corrected loader */ + BLACKLIST_LOADER(MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, atomwide_serial_loader), + BLACKLIST_LOADER(MANU_OAK, PROD_OAK_SCSI, oak_scsi_loader), + +/* Unsupported cards with no loader */ +BLACKLIST_NOLOADER(MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI), +BLACKLIST_NOLOADER(MANU_MCS, PROD_MCS_CONNECT32) +}; + +extern int setup_arm_irq(int, struct irqaction *); + +/* + * from linux/arch/arm/kernel/irq.c + */ +extern void do_ecard_IRQ(int irq, struct pt_regs *); + +static ecard_t expcard[MAX_ECARDS]; +static signed char irqno_to_expcard[16]; +static unsigned int ecard_numcards, ecard_numirqcards; +static unsigned int have_expmask; +static unsigned long kmem; + +static void ecard_def_irq_enable (ecard_t *ec, int irqnr) +{ +#ifdef HAS_EXPMASK + if (irqnr < 4 && have_expmask) { + have_expmask |= 1 << irqnr; + EXPMASK_ENABLE = have_expmask; + } +#endif +} + +static void ecard_def_irq_disable (ecard_t *ec, int irqnr) +{ +#ifdef HAS_EXPMASK + if (irqnr < 4 && have_expmask) { + have_expmask &= ~(1 << irqnr); + EXPMASK_ENABLE = have_expmask; + } +#endif +} + +static void ecard_def_fiq_enable (ecard_t *ec, int fiqnr) +{ + panic ("ecard_def_fiq_enable called - impossible"); +} + +static void ecard_def_fiq_disable (ecard_t *ec, int fiqnr) +{ + panic ("ecard_def_fiq_disable called - impossible"); +} + +static expansioncard_ops_t ecard_default_ops = { + ecard_def_irq_enable, + ecard_def_irq_disable, + ecard_def_fiq_enable, + ecard_def_fiq_disable +}; + +/* + * Enable and disable interrupts from expansion cards. + * (interrupts are disabled for these functions). + * + * They are not meant to be called directly, but via enable/disable_irq. + */ +void ecard_enableirq (unsigned int irqnr) +{ + if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) { + ecard_t *ec = expcard + irqno_to_expcard[irqnr]; + + if (!ec->ops) + ec->ops = &ecard_default_ops; + + if (ec->claimed && ec->ops->irqenable) + ec->ops->irqenable (ec, irqnr); + else + printk (KERN_ERR "ecard: rejecting request to " + "enable IRQs for %d\n", irqnr); + } +} + +void ecard_disableirq (unsigned int irqnr) +{ + if (irqnr < MAX_ECARDS && irqno_to_expcard[irqnr] != -1) { + ecard_t *ec = expcard + irqno_to_expcard[irqnr]; + + if (!ec->ops) + ec->ops = &ecard_default_ops; + + if (ec->ops && ec->ops->irqdisable) + ec->ops->irqdisable (ec, irqnr); + } +} + +void ecard_enablefiq (unsigned int fiqnr) +{ + if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) { + ecard_t *ec = expcard + irqno_to_expcard[fiqnr]; + + if (!ec->ops) + ec->ops = &ecard_default_ops; + + if (ec->claimed && ec->ops->fiqenable) + ec->ops->fiqenable (ec, fiqnr); + else + printk (KERN_ERR "ecard: rejecting request to " + "enable FIQs for %d\n", fiqnr); + } +} + +void ecard_disablefiq (unsigned int fiqnr) +{ + if (fiqnr < MAX_ECARDS && irqno_to_expcard[fiqnr] != -1) { + ecard_t *ec = expcard + irqno_to_expcard[fiqnr]; + + if (!ec->ops) + ec->ops = &ecard_default_ops; + + if (ec->ops->fiqdisable) + ec->ops->fiqdisable (ec, fiqnr); + } +} + +static void *ecard_malloc(int len) +{ + int r; + + len = (len + 3) & ~3; + + if (kmem) { + r = kmem; + kmem += len; + return (void *)r; + } else + return kmalloc(len, GFP_KERNEL); +} + +static void ecard_irq_noexpmask(int intr_no, void *dev_id, struct pt_regs *regs) +{ + const int num_cards = ecard_numirqcards; + int i, called = 0; + + mask_irq (IRQ_EXPANSIONCARD); + for (i = 0; i < num_cards; i++) { + if (expcard[i].claimed && expcard[i].irq && + (!expcard[i].irqmask || + expcard[i].irqaddr[0] & expcard[i].irqmask)) { + do_ecard_IRQ(expcard[i].irq, regs); + called ++; + } + } + cli (); + unmask_irq (IRQ_EXPANSIONCARD); + if (called == 0) + printk (KERN_WARNING "Wild interrupt from backplane?\n"); +} + +#ifdef HAS_EXPMASK +static unsigned char priority_masks[] = +{ + 0xf0, 0xf1, 0xf3, 0xf7, 0xff, 0xff, 0xff, 0xff +}; + +static unsigned char first_set[] = +{ + 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00 +}; + +static void ecard_irq_expmask (int intr_no, void *dev_id, struct pt_regs *regs) +{ + const unsigned int statusmask = 15; + unsigned int status; + + status = EXPMASK_STATUS & statusmask; + if (status) { + unsigned int irqno; + ecard_t *ec; +again: + irqno = first_set[status]; + ec = expcard + irqno_to_expcard[irqno]; + if (ec->claimed) { + unsigned int oldexpmask; + /* + * this ugly code is so that we can operate a prioritorising system. + * Card 0 highest priority + * Card 1 + * Card 2 + * Card 3 lowest priority + * Serial cards should go in 0/1, ethernet/scsi in 2/3 + * otherwise you will lose serial data at high speeds! + */ + oldexpmask = have_expmask; + EXPMASK_ENABLE = (have_expmask &= priority_masks[irqno]); + sti (); + do_ecard_IRQ (ec->irq, regs); + cli (); + EXPMASK_ENABLE = have_expmask = oldexpmask; + status = EXPMASK_STATUS & statusmask; + if (status) + goto again; + } else { + printk (KERN_WARNING "card%d: interrupt from unclaimed card???\n", irqno); + EXPMASK_ENABLE = (have_expmask &= ~(1 << irqno)); + } + } else + printk (KERN_WARNING "Wild interrupt from backplane (masks)\n"); +} + +static int ecard_checkirqhw (void) +{ + int found; + + EXPMASK_ENABLE = 0x00; + EXPMASK_STATUS = 0xff; + found = ((EXPMASK_STATUS & 15) == 0); + EXPMASK_ENABLE = 0xff; + + return found; +} +#endif + +static void ecard_readbytes (void *addr, ecard_t *ec, int off, int len, int useld) +{ + extern int ecard_loader_read(int off, volatile unsigned int pa, loader_t loader); + unsigned char *a = (unsigned char *)addr; + + if (ec->slot_no == 8) { + static unsigned int lowaddress; + unsigned int laddr, haddr; + unsigned char byte = 0; /* keep gcc quiet */ + + laddr = off & 4095; /* number of bytes to read from offset + base addr */ + haddr = off >> 12; /* offset into card from base addr */ + + if (haddr > 256) + return; + + /* + * If we require a low address or address 0, then reset, and start again... + */ + if (!off || lowaddress > laddr) { + outb (0, ec->podaddr); + lowaddress = 0; + } + while (lowaddress <= laddr) { + byte = inb (ec->podaddr + haddr); + lowaddress += 1; + } + while (len--) { + *a++ = byte; + if (len) { + byte = inb (ec->podaddr + haddr); + lowaddress += 1; + } + } + } else { + if (!useld || !ec->loader) { + while(len--) + *a++ = inb(ec->podaddr + (off++)); + } else { + while(len--) { + *(unsigned long *)0x108 = 0; /* hack for some loaders!!! */ + *a++ = ecard_loader_read(off++, BUS_ADDR(ec->podaddr), ec->loader); + } + } + } +} + +/* + * This is called to reset the loaders for each expansion card on reboot. + * + * This is required to make sure that the card is in the correct state + * that RiscOS expects it to be. + */ +void ecard_reset (int card) +{ + extern int ecard_loader_reset (volatile unsigned int pa, loader_t loader); + + if (card >= ecard_numcards) + return; + + if (card < 0) { + for (card = 0; card < ecard_numcards; card++) + if (expcard[card].loader) + ecard_loader_reset (BUS_ADDR(expcard[card].podaddr), + expcard[card].loader); + } else + if (expcard[card].loader) + ecard_loader_reset (BUS_ADDR(expcard[card].podaddr), + expcard[card].loader); + +#ifdef HAS_EXPMASK + if (have_expmask) { + have_expmask |= ~0; + EXPMASK_ENABLE = have_expmask; + } +#endif +} + +static unsigned int ecard_startcard; + +void ecard_startfind (void) +{ + ecard_startcard = 0; +} + +ecard_t *ecard_find (int cld, const card_ids *cids) +{ + int card; + if (!cids) { + for (card = ecard_startcard; card < ecard_numcards; card++) + if (!expcard[card].claimed && + ((expcard[card].cld.ecld ^ cld) & 0x78) == 0) + break; + } else { + for (card = ecard_startcard; card < ecard_numcards; card++) { + unsigned int manufacturer, product; + int i; + + if (expcard[card].claimed) + continue; + + manufacturer = expcard[card].cld.manufacturer; + product = expcard[card].cld.product; + + for (i = 0; cids[i].manufacturer != 65535; i++) + if (manufacturer == cids[i].manufacturer && + product == cids[i].product) + break; + + if (cids[i].manufacturer != 65535) + break; + } + } + ecard_startcard = card + 1; + return card < ecard_numcards ? &expcard[card] : NULL; +} + +int ecard_readchunk (struct in_chunk_dir *cd, ecard_t *ec, int id, int num) +{ + struct ex_chunk_dir excd; + int index = 16; + int useld = 0; + + while(1) { + ecard_readbytes(&excd, ec, index, 8, useld); + index += 8; + if (c_id(&excd) == 0) { + if (!useld && ec->loader) { + useld = 1; + index = 0; + continue; + } + return 0; + } + if (c_id(&excd) == 0xf0) { /* link */ + index = c_start(&excd); + continue; + } + if (c_id(&excd) == 0x80) { /* loader */ + if (!ec->loader) { + ec->loader = (loader_t)ecard_malloc(c_len(&excd)); + ecard_readbytes(ec->loader, ec, (int)c_start(&excd), c_len(&excd), useld); + } + continue; + } + if (c_id(&excd) == id && num-- == 0) + break; + } + + if (c_id(&excd) & 0x80) { + switch (c_id(&excd) & 0x70) { + case 0x70: + ecard_readbytes((unsigned char *)excd.d.string, ec, + (int)c_start(&excd), c_len(&excd), useld); + break; + case 0x00: + break; + } + } + cd->start_offset = c_start(&excd); + memcpy (cd->d.string, excd.d.string, 256); + return 1; +} + +unsigned int ecard_address (ecard_t *ec, card_type_t memc, card_speed_t speed) +{ + switch (ec->slot_no) { + case 0: + case 1: + case 2: + case 3: + return (memc ? MEMCECIO_BASE : IOCECIO_BASE + (speed << 17)) + (ec->slot_no << 12); +#ifdef IOCEC4IO_BASE + case 4: + case 5: + case 6: + case 7: + return (memc ? 0 : IOCEC4IO_BASE + (speed << 17)) + ((ec->slot_no - 4) << 12); +#endif +#ifdef MEMCEC8IO_BASE + case 8: + return MEMCEC8IO_BASE; +#endif + } + return 0; +} + +/* + * Probe for an expansion card. + * + * If bit 1 of the first byte of the card is set, + * then the card does not exist. + */ +static int ecard_probe (int card, int freeslot) +{ + ecard_t *ec = expcard + freeslot; + struct ex_ecld excld; + const char *card_desc = NULL; + int i; + + irqno_to_expcard[card] = -1; + + ec->slot_no = card; + if ((ec->podaddr = ecard_address (ec, 0, ECARD_SYNC)) == 0) + return 0; + + excld.r_ecld = 2; + ecard_readbytes (&excld, ec, 0, 16, 0); + if (excld.r_ecld & 2) + return 0; + + irqno_to_expcard[card] = freeslot; + + ec->irq = -1; + ec->fiq = -1; + ec->cld.ecld = e_ecld(&excld); + ec->cld.manufacturer = e_manu(&excld); + ec->cld.product = e_prod(&excld); + ec->cld.country = e_country(&excld); + ec->cld.fiqmask = e_fiqmask(&excld); + ec->cld.irqmask = e_irqmask(&excld); + ec->cld.fiqaddr = e_fiqaddr(&excld); + ec->cld.irqaddr = e_irqaddr(&excld); + ec->fiqaddr = + ec->irqaddr = (unsigned char *)BUS_ADDR(ec->podaddr); + ec->fiqmask = 4; + ec->irqmask = 1; + ec->ops = &ecard_default_ops; + + for (i = 0; i < sizeof (blacklist) / sizeof (*blacklist); i++) + if (blacklist[i].manufacturer == ec->cld.manufacturer && + blacklist[i].product == ec->cld.product) { + ec->loader = blacklist[i].loader; + card_desc = blacklist[i].type; + break; + } + + if (card != 8) { + ec->irq = 32 + card; +#if 0 + ec->fiq = 96 + card; +#endif + } else { + ec->irq = 11; + ec->fiq = -1; + } + + if ((ec->cld.ecld & 0x78) == 0) { + struct in_chunk_dir incd; + printk ("\n %d: [%04X:%04X] ", card, ec->cld.manufacturer, ec->cld.product); + if (e_is (&excld)) { + ec->fiqmask = e_fiqmask (&excld); + ec->irqmask = e_irqmask (&excld); + ec->fiqaddr += e_fiqaddr (&excld); + ec->irqaddr += e_irqaddr (&excld); + } + if (!card_desc && e_cd (&excld) && ecard_readchunk (&incd, ec, 0xf5, 0)) + card_desc = incd.d.string; + if (card_desc) + printk ("%s", card_desc); + else + printk ("*Unknown*"); + } else + printk("\n %d: Simple card %d\n", card, (ec->cld.ecld >> 3) & 15); + return 1; +} + +static struct irqaction irqexpansioncard = { ecard_irq_noexpmask, SA_INTERRUPT, 0, "expansion cards", NULL, NULL }; + +/* + * Initialise the expansion card system. + * Locate all hardware - interrupt management and + * actual cards. + */ +unsigned long ecard_init(unsigned long start_mem) +{ + int i, nc = 0; + + kmem = (start_mem | 3) & ~3; + memset (expcard, 0, sizeof (expcard)); + +#ifdef HAS_EXPMASK + if (ecard_checkirqhw()) { + printk (KERN_DEBUG "Expansion card interrupt management hardware found\n"); + irqexpansioncard.handler = ecard_irq_expmask; + have_expmask = -1; + } +#endif + printk("Installed expansion cards:"); + + /* + * First of all, probe all cards on the expansion card interrupt line + */ + for (i = 0; i < 4; i++) + if (ecard_probe (i, nc)) + nc += 1; + else + have_expmask &= ~(1< +#include + +#include +#include +#include + +#include "../lib/constants.h" + + .text + +@ Offsets into task structure +@ --------------------------- +@ +#define STATE 0 +#define COUNTER 4 +#define PRIORITY 8 +#define FLAGS 12 +#define SIGPENDING 16 + +#define PF_TRACESYS 0x20 + +@ Bad Abort numbers +@ ----------------- +@ +#define BAD_PREFETCH 0 +#define BAD_DATA 1 +#define BAD_ADDREXCPTN 2 +#define BAD_IRQ 3 +#define BAD_UNDEFINSTR 4 + +@ OS version number used in SWIs +@ RISC OS is 0 +@ RISC iX is 8 +@ +#define OS_NUMBER 9 + +@ +@ Stack format (ensured by USER_* and SVC_*) +@ +#define S_OLD_R0 64 +#define S_PSR 60 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +#ifdef IOC_BASE +/* IOC / IOMD based hardware */ + .equ ioc_base_high, IOC_BASE & 0xff000000 + .equ ioc_base_low, IOC_BASE & 0x00ff0000 + .macro disable_fiq + mov r12, #ioc_base_high + .if ioc_base_low + orr r12, r12, #ioc_base_low + .endif + strb r12, [r12, #0x38] @ Disable FIQ register + .endm + + .macro get_irqnr_and_base, irqnr, base + mov r4, #ioc_base_high @ point at IOC + .if ioc_base_low + orr r4, r4, #ioc_base_low + .endif + ldrb \irqnr, [r4, #0x24] @ get high priority first + adr \base, irq_prio_h + teq \irqnr, #0 + ldreqb \irqnr, [r4, #0x14] @ get low priority + adreq \base, irq_prio_l + .endm + +/* + * Interrupt table (incorporates priority) + */ + .macro irq_prio_table +irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .endm +#else +#error Unknown architecture +#endif + +/*============================================================================= + * For entry-common.S + */ + + .macro save_user_regs + str r0, [sp, #-4]! + str lr, [sp, #-4]! + sub sp, sp, #15*4 + stmia sp, {r0 - lr}^ + mov r0, r0 + .endm + + .macro restore_user_regs + ldmia sp, {r0 - lr}^ + mov r0, r0 + add sp, sp, #15*4 + ldr lr, [sp], #8 + movs pc, lr + .endm + + .macro mask_pc, rd, rm + bic \rd, \rm, #PCMASK + .endm + + .macro arm700_bug_check, instr, temp + .endm + + .macro enable_irqs, temp + teqp pc, #0x00000003 + .endm + + .macro initialise_traps_extra + .endm + + .macro get_current_task, rd + mov \rd, sp, lsr #13 + mov \rd, \rd, lsl #13 + .endm + + /* + * Like adr, but force SVC mode (if required) + */ + .macro adrsvc, cond, reg, label + adr\cond \reg, \label + orr\cond \reg, \reg, #3 + .endm + +#if 0 +/* + * Uncomment these if you wish to get more debugging into about data aborts. + */ +#define FAULT_CODE_LDRSTRPOST 0x80 +#define FAULT_CODE_LDRSTRPRE 0x40 +#define FAULT_CODE_LDRSTRREG 0x20 +#define FAULT_CODE_LDMSTM 0x10 +#define FAULT_CODE_LDCSTC 0x08 +#endif +#define FAULT_CODE_PREFETCH 0x04 +#define FAULT_CODE_WRITE 0x02 +#define FAULT_CODE_USER 0x01 + + +#define SVC_SAVE_ALL \ + str sp, [sp, #-16]! ;\ + str lr, [sp, #8] ;\ + str lr, [sp, #4] ;\ + stmfd sp!, {r0 - r12} ;\ + mov r0, #-1 ;\ + str r0, [sp, #S_OLD_R0] ;\ + mov fp, #0 + +#define SVC_IRQ_SAVE_ALL \ + str sp, [sp, #-16]! ;\ + str lr, [sp, #4] ;\ + ldr lr, .LCirq ;\ + ldr lr, [lr] ;\ + str lr, [sp, #8] ;\ + stmfd sp!, {r0 - r12} ;\ + mov r0, #-1 ;\ + str r0, [sp, #S_OLD_R0] ;\ + mov fp, #0 + +#define USER_RESTORE_ALL \ + ldmia sp, {r0 - lr}^ ;\ + mov r0, r0 ;\ + add sp, sp, #15*4 ;\ + ldr lr, [sp], #8 ;\ + movs pc, lr + +#define SVC_RESTORE_ALL \ + ldmfd sp, {r0 - pc}^ + +/*============================================================================= + * Undefined FIQs + *----------------------------------------------------------------------------- + */ +_unexp_fiq: ldr sp, .LCfiq + mov r12, #IOC_BASE + strb r12, [r12, #0x38] @ Disable FIQ register + teqp pc, #0x0c000003 + mov r0, r0 + stmfd sp!, {r0 - r3, ip, lr} + adr r0, Lfiqmsg + bl SYMBOL_NAME(printk) + ldmfd sp!, {r0 - r3, ip, lr} + teqp pc, #0x0c000001 + mov r0, r0 + movs pc, lr + +Lfiqmsg: .ascii "*** Unexpeced FIQ\n\0" + .align + +.LCfiq: .word __temp_fiq +.LCirq: .word __temp_irq + +/*============================================================================= + * Undefined instruction handler + *----------------------------------------------------------------------------- + * Handles floating point instructions + */ +vector_undefinstr: + tst lr,#3 + bne __und_svc + save_user_regs + mov fp, #0 + teqp pc, #I_BIT | MODE_SVC +.Lbug_undef: + adr r1, .LC2 + ldmia r1, {r1, r4} + ldr r1, [r1] + get_current_task r2 + teq r1, r2 + stmnefd sp!, {ip, lr} + blne SYMBOL_NAME(math_state_restore) + ldmnefd sp!, {ip, lr} + ldr pc, [r4] @ Call FP module USR entry point + + .globl SYMBOL_NAME(fpundefinstr) +SYMBOL_NAME(fpundefinstr): @ Called by FP module on undefined instr +SYMBOL_NAME(fpundefinstrsvc): + mov r0, lr + mov r1, sp + teqp pc, #MODE_SVC + bl SYMBOL_NAME(do_undefinstr) + b ret_from_exception @ Normal FP exit + +__und_svc: SVC_SAVE_ALL @ Non-user mode + mask_pc r0, lr + and r2, lr, #3 + sub r0, r0, #4 + mov r1, sp + bl SYMBOL_NAME(do_undefinstr) + SVC_RESTORE_ALL + +.LC2: .word SYMBOL_NAME(last_task_used_math) + .word SYMBOL_NAME(fp_enter) + +/*============================================================================= + * Prefetch abort handler + *----------------------------------------------------------------------------- + */ + +vector_prefetch: + sub lr, lr, #4 + tst lr, #3 + bne __pabt_invalid + save_user_regs + teqp pc, #0x00000003 @ NOT a problem - doesnt change mode + mask_pc r0, lr @ Address of abort + mov r1, #FAULT_CODE_PREFETCH|FAULT_CODE_USER @ Error code + mov r2, sp @ Tasks registers + bl SYMBOL_NAME(do_PrefetchAbort) + teq r0, #0 @ If non-zero, we believe this abort.. + bne ret_from_sys_call +#ifdef DEBUG_UNDEF + adr r0, t + bl SYMBOL_NAME(printk) +#endif + ldr lr, [sp,#S_PC] @ program to test this on. I think its + b .Lbug_undef @ broken at the moment though!) + +__pabt_invalid: SVC_SAVE_ALL + mov r0, sp @ Prefetch aborts are definitely *not* + mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant + and r2, lr, #3 @ recover from this problem. + b SYMBOL_NAME(bad_mode) + +#ifdef DEBUG_UNDEF +t: .ascii "*** undef ***\r\n\0" + .align +#endif + +/*============================================================================= + * Address exception handler + *----------------------------------------------------------------------------- + * These aren't too critical. + * (they're not supposed to happen). + * In order to debug the reason for address exceptions in non-user modes, + * we have to obtain all the registers so that we can see what's going on. + */ + +vector_addrexcptn: + sub lr, lr, #8 + tst lr, #3 + bne Laddrexcptn_not_user + save_user_regs + teq pc, #0x00000003 + mask_pc r0, lr @ Point to instruction + mov r1, sp @ Point to registers + mov r2, #0x400 + mov lr, pc + bl SYMBOL_NAME(do_excpt) + b ret_from_exception + +Laddrexcptn_not_user: + SVC_SAVE_ALL + and r2, lr, #3 + teq r2, #3 + bne Laddrexcptn_illegal_mode + teqp pc, #0x00000003 @ NOT a problem - doesnt change mode + mask_pc r0, lr + mov r1, sp + orr r2, r2, #0x400 + bl SYMBOL_NAME(do_excpt) + ldmia sp, {r0 - lr} @ I cant remember the reason I changed this... + add sp, sp, #15*4 + movs pc, lr + +Laddrexcptn_illegal_mode: + mov r0, sp + str lr, [sp, #-4]! + orr r1, r2, #0x0c000000 + teqp r1, #0 @ change into mode (wont be user mode) + mov r0, r0 + mov r1, r8 @ Any register from r8 - r14 can be banked + mov r2, r9 + mov r3, r10 + mov r4, r11 + mov r5, r12 + mov r6, r13 + mov r7, r14 + teqp pc, #0x04000003 @ back to svc + mov r0, r0 + stmfd sp!, {r1-r7} + ldmia r0, {r0-r7} + stmfd sp!, {r0-r7} + mov r0, sp + mov r1, #BAD_ADDREXCPTN + b SYMBOL_NAME(bad_mode) + +/*============================================================================= + * Interrupt (IRQ) handler + *----------------------------------------------------------------------------- + * Note: if in user mode, then *no* kernel routine is running, so dont have + * to save svc lr + * (r13 points to irq temp save area) + */ + +vector_IRQ: ldr r13, .LCirq @ Ill leave this one in just in case... + sub lr, lr, #4 + str lr, [r13] + tst lr, #3 + bne __irq_svc + teqp pc, #0x08000003 + mov r0, r0 + ldr lr, .LCirq + ldr lr, [lr] + save_user_regs + +1: get_irqnr_and_base r6, r5 + teq r6, #0 + ldrneb r0, [r5, r6] @ get IRQ number + movne r1, sp + @ + @ routine called with r0 = irq number, r1 = struct pt_regs * + @ + adr lr, 1b + orr lr, lr, #3 @ Force SVC + bne do_IRQ + b ret_with_reschedule + + irq_prio_table + +__irq_svc: teqp pc, #0x08000003 + mov r0, r0 + SVC_IRQ_SAVE_ALL + and r2, lr, #3 + teq r2, #3 + bne __irq_invalid +1: get_irqnr_and_base r6, r5 + teq r6, #0 + ldrneb r0, [r5, r6] @ get IRQ number + movne r1, sp + @ + @ routine called with r0 = irq number, r1 = struct pt_regs * + @ + adr lr, 1b + orr lr, lr, #3 @ Force SVC + bne do_IRQ @ Returns to 1b + SVC_RESTORE_ALL + +__irq_invalid: mov r0, sp + mov r1, #BAD_IRQ + b SYMBOL_NAME(bad_mode) + +/*============================================================================= + * Data abort handler code + *----------------------------------------------------------------------------- + * + * This handles both exceptions from user and SVC modes, computes the address + * range of the problem, and does any correction that is required. It then + * calls the kernel data abort routine. + * + * This is where I wish that the ARM would tell you which address aborted. + */ + +vector_data: sub lr, lr, #8 @ Correct lr + tst lr, #3 + bne Ldata_not_user + save_user_regs + teqp pc, #0x00000003 @ NOT a problem - doesnt change mode + mask_pc r0, lr + mov r2, #FAULT_CODE_USER + bl Ldata_do + b ret_from_exception + +Ldata_not_user: + SVC_SAVE_ALL + and r2, lr, #3 + teq r2, #3 + bne Ldata_illegal_mode + tst lr, #0x08000000 + teqeqp pc, #0x00000003 @ NOT a problem - doesnt change mode + mask_pc r0, lr + mov r2, #0 + bl Ldata_do + SVC_RESTORE_ALL + +Ldata_illegal_mode: + mov r0, sp + mov r1, #BAD_DATA + b SYMBOL_NAME(bad_mode) + +Ldata_do: mov r3, sp + ldr r4, [r0] @ Get instruction + tst r4, #1 << 20 @ Check to see if it is a write instruction + orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction + mov r1, r4, lsr #22 @ Now branch to the relevent processing routine + and r1, r1, #15 << 2 + add pc, pc, r1 + movs pc, lr + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_ldrstr_post @ ldr rd, [rn], #m + b Ldata_ldrstr_numindex @ ldr rd, [rn, #m] @ RegVal + b Ldata_ldrstr_post @ ldr rd, [rn], rm + b Ldata_ldrstr_regindex @ ldr rd, [rn, rm] + b Ldata_ldmstm @ ldm*a rn, + b Ldata_ldmstm @ ldm*b rn, + b Ldata_unknown + b Ldata_unknown + b Ldata_ldrstr_post @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m + b Ldata_ldcstc_pre @ ldc rd, [rn, #m] + b Ldata_unknown +Ldata_unknown: @ Part of jumptable + ldr r3, [sp, #15 * 4] + str r3, [sp, #-4]! + mov r1, r1, lsr #2 + mov r2, r0 + mov r3, r4 + adr r0, Ltt + bl SYMBOL_NAME(printk) +Llpxx: b Llpxx + +Ltt: .ascii "Unknown data abort code %d [pc=%p, *pc=%p]\nLR=%p\0" + .align + +Ldata_ldrstr_post: + mov r0, r4, lsr #14 @ Get Rn + and r0, r0, #15 << 2 @ Mask out reg. + teq r0, #15 << 2 + ldr r0, [r3, r0] @ Get register + biceq r0, r0, #PCMASK + mov r1, r0 +#ifdef FAULT_CODE_LDRSTRPOST + orr r2, r2, #FAULT_CODE_LDRSTRPOST +#endif + b SYMBOL_NAME(do_DataAbort) + +Ldata_ldrstr_numindex: + mov r0, r4, lsr #14 @ Get Rn + and r0, r0, #15 << 2 @ Mask out reg. + teq r0, #15 << 2 + ldr r0, [r3, r0] @ Get register + biceq r0, r0, #PCMASK + mov r1, r4, lsl #20 + tst r4, #1 << 23 + addne r0, r0, r1, lsr #20 + subeq r0, r0, r1, lsr #20 + mov r1, r0 +#ifdef FAULT_CODE_LDRSTRPRE + orr r2, r2, #FAULT_CODE_LDRSTRPRE +#endif + b SYMBOL_NAME(do_DataAbort) + +Ldata_ldrstr_regindex: + mov r0, r4, lsr #14 @ Get Rn + and r0, r0, #15 << 2 @ Mask out reg. + teq r0, #15 << 2 + ldr r0, [r3, r0] @ Get register + biceq r0, r0, #PCMASK + and r7, r4, #15 + teq r7, #15 @ Check for PC + ldr r7, [r3, r7, lsl #2] @ Get Rm + biceq r7, r7, #PCMASK + and r8, r4, #0x60 @ Get shift types + mov r9, r4, lsr #7 @ Get shift amount + and r9, r9, #31 + teq r8, #0 + moveq r7, r7, lsl r9 + teq r8, #0x20 @ LSR shift + moveq r7, r7, lsr r9 + teq r8, #0x40 @ ASR shift + moveq r7, r7, asr r9 + teq r8, #0x60 @ ROR shift + moveq r7, r7, ror r9 + tst r4, #1 << 23 + addne r0, r0, r7 + subeq r0, r0, r7 @ Apply correction + mov r1, r0 +#ifdef FAULT_CODE_LDRSTRREG + orr r2, r2, #FAULT_CODE_LDRSTRREG +#endif + b SYMBOL_NAME(do_DataAbort) + +Ldata_ldmstm: + mov r7, #0x11 + orr r7, r7, r7, lsl #8 + and r0, r4, r7 + and r1, r4, r7, lsl #1 + add r0, r0, r1, lsr #1 + and r1, r4, r7, lsl #2 + add r0, r0, r1, lsr #2 + and r1, r4, r7, lsl #3 + add r0, r0, r1, lsr #3 + add r0, r0, r0, lsr #8 + add r0, r0, r0, lsr #4 + and r7, r0, #15 @ r7 = no. of registers to transfer. + mov r5, r4, lsr #14 @ Get Rn + and r5, r5, #15 << 2 + ldr r0, [r3, r5] @ Get reg + eor r6, r4, r4, lsl #2 + tst r6, #1 << 23 @ Check inc/dec ^ writeback + rsbeq r7, r7, #0 + add r7, r0, r7, lsl #2 @ Do correction (signed) + subne r1, r7, #1 + subeq r1, r0, #1 + moveq r0, r7 + tst r4, #1 << 21 @ Check writeback + strne r7, [r3, r5] + eor r6, r4, r4, lsl #1 + tst r6, #1 << 24 @ Check Pre/Post ^ inc/dec + addeq r0, r0, #4 + addeq r1, r1, #4 + teq r5, #15*4 @ CHECK FOR PC + biceq r1, r1, #PCMASK + biceq r0, r0, #PCMASK +#ifdef FAULT_CODE_LDMSTM + orr r2, r2, #FAULT_CODE_LDMSTM +#endif + b SYMBOL_NAME(do_DataAbort) + +Ldata_ldcstc_pre: + mov r0, r4, lsr #14 @ Get Rn + and r0, r0, #15 << 2 @ Mask out reg. + teq r0, #15 << 2 + ldr r0, [r3, r0] @ Get register + biceq r0, r0, #PCMASK + mov r1, r4, lsl #24 @ Get offset + tst r4, #1 << 23 + addne r0, r0, r1, lsr #24 + subeq r0, r0, r1, lsr #24 + mov r1, r0 +#ifdef FAULT_CODE_LDCSTC + orr r2, r2, #FAULT_CODE_LDCSTC +#endif + b SYMBOL_NAME(do_DataAbort) + +#include "entry-common.S" + + .data + +__temp_irq: .word 0 @ saved lr_irq +__temp_fiq: .space 128 diff -ur --new-file old/linux/arch/arm/kernel/entry-armv.S new/linux/arch/arm/kernel/entry-armv.S --- old/linux/arch/arm/kernel/entry-armv.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/entry-armv.S Sat Feb 21 03:28:21 1998 @@ -0,0 +1,671 @@ +/* + * linux/arch/arm/kernel/entry-armv.S + * + * Copyright (C) 1996,1997,1998 Russell King. + * ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk) + * + * Low-level vector interface routines + * + * Note: there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes + * it to save wrong values... Be aware! + */ +#include /* for CONFIG_ARCH_EBSA110 /* +#include +#include + +#include +#include +#include + +#include "../lib/constants.h" + + .text + +@ Offsets into task structure +@ --------------------------- +@ +#define STATE 0 +#define COUNTER 4 +#define PRIORITY 8 +#define FLAGS 12 +#define SIGPENDING 16 + +#define PF_TRACESYS 0x20 + +@ Bad Abort numbers +@ ----------------- +@ +#define BAD_PREFETCH 0 +#define BAD_DATA 1 +#define BAD_ADDREXCPTN 2 +#define BAD_IRQ 3 +#define BAD_UNDEFINSTR 4 + +@ OS version number used in SWIs +@ RISC OS is 0 +@ RISC iX is 8 +@ +#define OS_NUMBER 9 + +@ +@ Stack format (ensured by USER_* and SVC_*) +@ +#define S_FRAME_SIZE 72 +#define S_OLD_R0 68 +#define S_PSR 64 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +#ifdef IOC_BASE +/* IOC / IOMD based hardware */ + .equ ioc_base_high, IOC_BASE & 0xff000000 + .equ ioc_base_low, IOC_BASE & 0x00ff0000 + .macro disable_fiq + mov r12, #ioc_base_high + .if ioc_base_low + orr r12, r12, #ioc_base_low + .endif + strb r12, [r12, #0x38] @ Disable FIQ register + .endm + + .macro get_irqnr_and_base, irqnr, base + mov r4, #ioc_base_high @ point at IOC + .if ioc_base_low + orr r4, r4, #ioc_base_low + .endif + ldrb \irqnr, [r4, #0x24] @ get high priority first + adr \base, irq_prio_h + teq \irqnr, #0 +#ifdef IOMD_BASE + ldreqb \irqnr, [r4, #0x1f4] @ get dma + adreq \base, irq_prio_d + teqeq \irqnr, #0 +#endif + ldreqb \irqnr, [r4, #0x14] @ get low priority + adreq \base, irq_prio_l + .endm + +/* + * Interrupt table (incorporates priority) + */ + .macro irq_prio_table +irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +#ifdef IOMD_BASE +irq_prio_d: .byte 0,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 20,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 23,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 22,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 + .byte 21,16,17,16,18,16,17,16,19,16,17,16,18,16,17,16 +#endif +irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .endm + +#elif defined(CONFIG_ARCH_EBSA110) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, base + mov r4, #0xf3000000 + ldrb \irqnr, [r4] @ get interrupts + adr \base, irq_prio_ebsa110 + .endm + + .macro irq_prio_table +irq_prio_ebsa110: + .byte 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 + .byte 4, 4, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 + .byte 5, 5, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 + .byte 5, 5, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 + + .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 + .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 + .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 + .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 + + .byte 7, 0, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 + .byte 4, 4, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 + .byte 5, 5, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 + .byte 5, 5, 1, 1, 2, 2, 2, 2, 3, 3, 1, 1, 2, 2, 2, 2 + + .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 + .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 + .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 + .byte 6, 6, 6, 6, 2, 2, 2, 2, 3, 3, 6, 6, 2, 2, 2, 2 + .endm + +#else +#error Unknown architecture +#endif + +/*============================================================================ + * For entry-common.S + */ + + .macro save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0 - r12 + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ @ Calling sp, lr + mov r7, r0 + mrs r6, spsr + mov r5, lr + stmia r8, {r5, r6, r7} @ Save calling PC, CPSR, OLD_R0 + .endm + + .macro restore_user_regs + mrs r0, cpsr @ disable IRQs + orr r0, r0, #I_BIT + msr cpsr, r0 + ldr r0, [sp, #S_PSR] @ Get calling cpsr + msr spsr, r0 @ save in spsr_svc + ldmia sp, {r0 - lr}^ @ Get calling r0 - lr + mov r0, r0 + add sp, sp, #S_PC + ldr lr, [sp], #S_FRAME_SIZE - S_PC @ Get PC and jump over PC, PSR, OLD_R0 + movs pc, lr @ return & move spsr_svc into cpsr + .endm + + .macro mask_pc, rd, rm + .endm + + .macro arm700_bug_check, instr, temp + and \temp, \instr, #0x0f000000 @ check for SWI + teq \temp, #0x0f000000 + bne .Larm700bug + .endm + + .macro enable_irqs, temp + mrs \temp, cpsr + bic \temp, \temp, #I_BIT + msr cpsr, \temp + .endm + + .macro initialise_traps_extra + mrs r0, cpsr + bic r0, r0, #31 + orr r0, r0, #0xd3 + msr cpsr, r0 + .endm + + +.Larm700bug: str lr, [r8] + ldr r0, [sp, #S_PSR] @ Get calling cpsr + msr spsr, r0 + ldmia sp, {r0 - lr}^ @ Get calling r0 - lr + mov r0, r0 + add sp, sp, #S_PC + ldr lr, [sp], #S_FRAME_SIZE - S_PC @ Get PC and jump over PC, PSR, OLD_R0 + movs pc, lr + + + .macro get_current_task, rd + mov \rd, sp, lsr #13 + mov \rd, \rd, lsl #13 + .endm + + /* + * Like adr, but force SVC mode (if required) + */ + .macro adrsvc, cond, reg, label + adr\cond \reg, \label + .endm + +/*============================================================================= + * Undefined FIQs + *----------------------------------------------------------------------------- + * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC + * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg. + * Basically to switch modes, we *HAVE* to clobber one register... brain + * damage alert! I don't think that we can execute any code in here in any + * other mode than FIQ... Ok you can switch to another mode, but you can't + * get out of that mode without clobbering one register. + */ +_unexp_fiq: disable_fiq + subs pc, lr, #4 + +/*============================================================================= + * Interrupt entry dispatcher + *----------------------------------------------------------------------------- + * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC + */ +vector_IRQ: @ + @ save mode specific registers + @ + ldr r13, .LCirq + sub lr, lr, #4 + str lr, [r13] @ save lr_IRQ + mrs lr, spsr + str lr, [r13, #4] @ save spsr_IRQ + @ + @ now branch to the relevent MODE handling routine + @ + mrs sp, cpsr @ switch to SVC mode + bic sp, sp, #31 + orr sp, sp, #0x13 + msr spsr, sp + and lr, lr, #15 + cmp lr, #4 + addlts pc, pc, lr, lsl #2 @ Changes mode and branches + b __irq_invalid @ 4 - 15 + b __irq_usr @ 0 (USR_26 / USR_32) + b __irq_invalid @ 1 (FIQ_26 / FIQ_32) + b __irq_invalid @ 2 (IRQ_26 / IRQ_32) + b __irq_svc @ 3 (SVC_26 / SVC_32) +/* + *------------------------------------------------------------------------------------------------ + * Undef instr entry dispatcher - dispatches it to the correct handler for the processor mode + *------------------------------------------------------------------------------------------------ + * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC + */ +.LCirq: .word __temp_irq +.LCund: .word __temp_und +.LCabt: .word __temp_abt + +vector_undefinstr: + @ + @ save mode specific registers + @ + ldr r13, [pc, #.LCund - . - 8] + str lr, [r13] + mrs lr, spsr + str lr, [r13, #4] + @ + @ now branch to the relevent MODE handling routine + @ + mrs sp, cpsr + bic sp, sp, #31 + orr sp, sp, #0x13 + msr spsr, sp + and lr, lr, #15 + cmp lr, #4 + addlts pc, pc, lr, lsl #2 @ Changes mode and branches + b __und_invalid @ 4 - 15 + b __und_usr @ 0 (USR_26 / USR_32) + b __und_invalid @ 1 (FIQ_26 / FIQ_32) + b __und_invalid @ 2 (IRQ_26 / IRQ_32) + b __und_svc @ 3 (SVC_26 / SVC_32) +/* + *------------------------------------------------------------------------------------------------ + * Prefetch abort dispatcher - dispatches it to the correct handler for the processor mode + *------------------------------------------------------------------------------------------------ + * Enter in ABT mode, spsr = USR CPSR, lr = USR PC + */ +vector_prefetch: + @ + @ save mode specific registers + @ + sub lr, lr, #4 + ldr r13, .LCabt + str lr, [r13] + mrs lr, spsr + str lr, [r13, #4] + @ + @ now branch to the relevent MODE handling routine + @ + mrs sp, cpsr + bic sp, sp, #31 + orr sp, sp, #0x13 + msr spsr, sp + and lr, lr, #15 + adds pc, pc, lr, lsl #2 @ Changes mode and branches + b __pabt_invalid @ 4 - 15 + b __pabt_usr @ 0 (USR_26 / USR_32) + b __pabt_invalid @ 1 (FIQ_26 / FIQ_32) + b __pabt_invalid @ 2 (IRQ_26 / IRQ_32) + b __pabt_invalid @ 3 (SVC_26 / SVC_32) +/* + *------------------------------------------------------------------------------------------------ + * Data abort dispatcher - dispatches it to the correct handler for the processor mode + *------------------------------------------------------------------------------------------------ + * Enter in ABT mode, spsr = USR CPSR, lr = USR PC + */ +vector_data: @ + @ save mode specific registers + @ + sub lr, lr, #8 + ldr r13, .LCabt + str lr, [r13] + mrs lr, spsr + str lr, [r13, #4] + @ + @ now branch to the relevent MODE handling routine + @ + mrs sp, cpsr + bic sp, sp, #31 + orr sp, sp, #0x13 + msr spsr, sp + and lr, lr, #15 + cmp lr, #4 + addlts pc, pc, lr, lsl #2 @ Changes mode & branches + b __dabt_invalid @ 4 - 15 + b __dabt_usr @ 0 (USR_26 / USR_32) + b __dabt_invalid @ 1 (FIQ_26 / FIQ_32) + b __dabt_invalid @ 2 (IRQ_26 / IRQ_32) + b __dabt_svc @ 3 (SVC_26 / SVC_32) + +/*============================================================================= + * Undefined instruction handler + *----------------------------------------------------------------------------- + * Handles floating point instructions + */ +__und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - r12} @ Save r0 - r12 + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ @ Save user r0 - r12 + ldr r4, .LCund + ldmia r4, {r5 - r7} + stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 + mov fp, #0 + + adr r1, .LC2 + ldmia r1, {r1, r4} + ldr r1, [r1] + get_current_task r2 + teq r1, r2 + blne SYMBOL_NAME(math_state_restore) + adrsvc, al, r9, SYMBOL_NAME(fpreturn) + adrsvc al, lr, SYMBOL_NAME(fpundefinstr) + ldr pc, [r4] @ Call FP module USR entry point + + .globl SYMBOL_NAME(fpundefinstr) +SYMBOL_NAME(fpundefinstr): @ Called by FP module on undefined instr + mov r0, lr + mov r1, sp + mrs r4, cpsr @ Enable interrupts + bic r4, r4, #I_BIT + msr cpsr, r4 + bl SYMBOL_NAME(do_undefinstr) + b ret_from_exception @ Normal FP exit + +__und_svc: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ save r0 - r12 + mov r6, lr + ldr r7, .LCund + ldmia r7, {r7 - r9} + add r5, sp, #S_FRAME_SIZE + add r4, sp, #S_SP + stmia r4, {r5 - r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro + + adr r1, .LC2 + ldmia r1, {r1, r4} + ldr r1, [r1] + mov r2, sp, lsr #13 + mov r2, r2, lsl #13 + teq r1, r2 + blne SYMBOL_NAME(math_state_restore) + adrsvc al, r9, SYMBOL_NAME(fpreturnsvc) + adrsvc al, lr, SYMBOL_NAME(fpundefinstrsvc) + ldr pc, [r4] @ Call FP module SVC entry point + + .globl SYMBOL_NAME(fpundefinstrsvc) +SYMBOL_NAME(fpundefinstrsvc): + mov r0, r5 @ unsigned long pc + mov r1, sp @ struct pt_regs *regs + bl SYMBOL_NAME(do_undefinstr) + + .globl SYMBOL_NAME(fpreturnsvc) +SYMBOL_NAME(fpreturnsvc): + ldr lr, [sp, #S_PSR] @ Get SVC cpsr + msr spsr, lr + ldmia sp, {r0 - pc}^ @ Restore SVC registers + +.LC2: .word SYMBOL_NAME(last_task_used_math) + .word SYMBOL_NAME(fp_enter) + +__und_invalid: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - lr} + mov r7, r0 + ldr r4, .LCund + ldmia r4, {r5, r6} @ Get UND/IRQ/FIQ/ABT pc, cpsr + add r4, sp, #S_PC + stmia r4, {r5, r6, r7} @ Save UND/IRQ/FIQ/ABT pc, cpsr, old_r0 + mov r0, sp @ struct pt_regs *regs + mov r1, #BAD_UNDEFINSTR @ int reason + and r2, r6, #31 @ int mode + b SYMBOL_NAME(bad_mode) @ Does not ever return... +/*============================================================================= + * Prefetch abort handler + *----------------------------------------------------------------------------- + */ +pabtmsg: .ascii "Pabt: %08lX\n\0" + .align +__pabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - r12} @ Save r0 - r12 + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ @ Save sp_usr lr_usr + ldr r4, .LCabt + ldmia r4, {r5 - r7} @ Get USR pc, cpsr + stmia r8, {r5 - r7} @ Save USR pc, cpsr, old_r0 + + mrs r7, cpsr @ Enable interrupts if they were + bic r7, r7, #I_BIT @ previously + msr cpsr, r7 + mov r0, r5 @ address (pc) + mov r1, sp @ regs + bl SYMBOL_NAME(do_PrefetchAbort) @ call abort handler + teq r0, #0 @ Does this still apply??? + bne ret_from_exception @ Return from exception +#ifdef DEBUG_UNDEF + adr r0, t + bl SYMBOL_NAME(printk) +#endif + mov r0, r5 + mov r1, sp + and r2, r6, #31 + bl SYMBOL_NAME(do_undefinstr) + ldr lr, [sp, #S_PSR] @ Get USR cpsr + msr spsr, lr + ldmia sp, {r0 - pc}^ @ Restore USR registers + +__pabt_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - lr} @ Save XXX r0 - lr + mov r7, r0 @ OLD R0 + ldr r4, .LCabt + ldmia r4, {r5 - r7} @ Get XXX pc, cpsr + add r4, sp, #S_PC + stmia r4, {r5 - r7} @ Save XXX pc, cpsr, old_r0 + mov r0, sp @ Prefetch aborts are definitely *not* + mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant + and r2, r6, #31 @ recover from this problem. + b SYMBOL_NAME(bad_mode) + +#ifdef DEBUG_UNDEF +t: .ascii "*** undef ***\r\n\0" + .align +#endif + +/*============================================================================= + * Address exception handler + *----------------------------------------------------------------------------- + * These aren't too critical. + * (they're not supposed to happen, and won't happen in 32-bit mode). + */ + +vector_addrexcptn: + b vector_addrexcptn + +/*============================================================================= + * Interrupt (IRQ) handler + *----------------------------------------------------------------------------- + */ +__irq_usr: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ save r0 - r12 + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ + ldr r4, .LCirq + ldmia r4, {r5 - r7} @ get saved PC, SPSR + stmia r8, {r5 - r7} @ save pc, psr, old_r0 +1: get_irqnr_and_base r6, r5 + teq r6, #0 + ldrneb r0, [r5, r6] @ get IRQ number + movne r1, sp + @ + @ routine called with r0 = irq number, r1 = struct pt_regs * + @ + adrsvc ne, lr, 1b + bne do_IRQ + b ret_with_reschedule + + irq_prio_table + +__irq_svc: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ save r0 - r12 + mov r6, lr + ldr r7, .LCirq + ldmia r7, {r7 - r9} + add r5, sp, #S_FRAME_SIZE + add r4, sp, #S_SP + stmia r4, {r5, r6, r7, r8, r9} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro +1: get_irqnr_and_base r6, r5 + teq r6, #0 + ldrneb r0, [r5, r6] @ get IRQ number + movne r1, sp + @ + @ routine called with r0 = irq number, r1 = struct pt_regs * + @ + adrsvc ne, lr, 1b + bne do_IRQ + ldr r0, [sp, #S_PSR] + msr spsr, r0 + ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr + +__irq_invalid: sub sp, sp, #S_FRAME_SIZE @ Allocate space on stack for frame + stmfd sp, {r0 - lr} @ Save r0 - lr + mov r7, #-1 + ldr r4, .LCirq + ldmia r4, {r5, r6} @ get saved pc, psr + add r4, sp, #S_PC + stmia r4, {r5, r6, r7} + mov fp, #0 + mov r0, sp + mov r1, #BAD_IRQ + b SYMBOL_NAME(bad_mode) + +/*============================================================================= + * Data abort handler code + *----------------------------------------------------------------------------- + */ +.LCprocfns: .word SYMBOL_NAME(processor) + +__dabt_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go + stmia sp, {r0 - r12} @ save r0 - r12 + add r3, sp, #S_PC + stmdb r3, {sp, lr}^ + ldr r0, .LCabt + ldmia r0, {r0 - r2} @ Get USR pc, cpsr + stmia r3, {r0 - r2} @ Save USR pc, cpsr, old_r0 + mov fp, #0 + mrs r2, cpsr @ Enable interrupts if they were + bic r2, r2, #I_BIT @ previously + msr cpsr, r2 + ldr r2, .LCprocfns + mov lr, pc + ldr pc, [r2, #8] @ call processor specific code + mov r3, sp + bl SYMBOL_NAME(do_DataAbort) + b ret_from_sys_call + +__dabt_svc: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ save r0 - r12 + ldr r2, .LCabt + add r0, sp, #S_FRAME_SIZE + add r5, sp, #S_SP + mov r1, lr + ldmia r2, {r2 - r4} @ get pc, cpsr + stmia r5, {r0 - r4} @ save sp_SVC, lr_SVC, pc, cpsr, old_ro + tst r3, #I_BIT + mrseq r0, cpsr @ Enable interrupts if they were + biceq r0, r0, #I_BIT @ previously + msreq cpsr, r0 + mov r0, r2 + ldr r2, .LCprocfns + mov lr, pc + ldr pc, [r2, #8] @ call processor specific code + mov r3, sp + bl SYMBOL_NAME(do_DataAbort) + ldr r0, [sp, #S_PSR] + msr spsr, r0 + ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr + +__dabt_invalid: sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - lr} @ Save SVC r0 - lr [lr *should* be intact] + mov r7, r0 + ldr r4, .LCabt + ldmia r4, {r5, r6} @ Get SVC pc, cpsr + add r4, sp, #S_PC + stmia r4, {r5, r6, r7} @ Save SVC pc, cpsr, old_r0 + mov r0, sp + mov r1, #BAD_DATA + and r2, r6, #31 + b SYMBOL_NAME(bad_mode) + + +#include "entry-common.S" + + .data + +__temp_irq: .word 0 @ saved lr_irq + .word 0 @ saved spsr_irq + .word -1 @ old_r0 +__temp_und: .word 0 @ Saved lr_und + .word 0 @ Saved spsr_und + .word -1 @ old_r0 +__temp_abt: .word 0 @ Saved lr_abt + .word 0 @ Saved spsr_abt + .word -1 @ old_r0 diff -ur --new-file old/linux/arch/arm/kernel/entry-common.S new/linux/arch/arm/kernel/entry-common.S --- old/linux/arch/arm/kernel/entry-common.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/entry-common.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,283 @@ +/* + *============================================================================= + * Low-level interface code + *----------------------------------------------------------------------------- + * Trap initialisation + *----------------------------------------------------------------------------- + * + * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20 + * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes + * some excess cycles). + * + * What we need to put into 0-0x1c are ldrs to branch to 0xC0000000 + * (the kernel). + * 0x1c onwards is reserved for FIQ, so I think that I will allocate 0xe0 onwards for + * the actuall address to jump to. + */ +/* + * these go into 0x00 + */ +.Lbranches: swi SYS_ERROR0 + ldr pc, .Lbranches + 0xe4 + ldr pc, .Lbranches + 0xe8 + ldr pc, .Lbranches + 0xec + ldr pc, .Lbranches + 0xf0 + ldr pc, .Lbranches + 0xf4 + ldr pc, .Lbranches + 0xf8 + ldr pc, .Lbranches + 0xfc +/* + * this is put into 0xe4 and above + */ +.Ljump_addresses: + .word vector_undefinstr @ 0xe4 + .word vector_swi @ 0xe8 + .word vector_prefetch @ 0xec + .word vector_data @ 0xf0 + .word vector_addrexcptn @ 0xf4 + .word vector_IRQ @ 0xf8 + .word _unexp_fiq @ 0xfc +/* + * initialise the trap system + */ +ENTRY(trap_init) + stmfd sp!, {r4 - r7, lr} + initialise_traps_extra + mov r0, #0xe4 + adr r1, .Ljump_addresses + ldmia r1, {r1 - r6} + stmia r0, {r1 - r6} + mov r0, #0 + adr r1, .Lbranches + ldmia r1, {r1 - r7} + stmia r0, {r1 - r7} + LOADREGS(fd, sp!, {r4 - r7, pc}) + +/*============================================================================= + * SWI handler + *----------------------------------------------------------------------------- + * + * We now handle sys-call tracing, and the errno in the task structure. + * Still have a problem with >4 arguments for functions. Theres only + * a couple of functions in the code that have 5 arguments, so Im not + * too worried. + */ + +#include "calls.S" + +vector_swi: save_user_regs + mov fp, #0 + mask_pc lr, lr + ldr r6, [lr, #-4]! @ get SWI instruction + arm700_bug_check r6, r7 + enable_irqs r7 + + bic r6, r6, #0xff000000 @ mask off SWI op-code + eor r6, r6, #OS_NUMBER<<20 @ check OS number + cmp r6, #NR_SYSCALLS @ check upper syscall limit + bcs 2f + + get_current_task r5 + ldr ip, [r5, #FLAGS] @ check for syscall tracing + tst ip, #PF_TRACESYS + bne 1f + + adr ip, SYMBOL_NAME(sys_call_table) + str r4, [sp, #-4]! @ new style: (r0 = arg1, r5 = arg5) + mov lr, pc + ldr pc, [ip, r6, lsl #2] @ call sys routine + add sp, sp, #4 + str r0, [sp, #S_R0] @ returned r0 + b ret_from_sys_call + +1: ldr r7, [sp, #S_IP] @ save old IP + mov r0, #0 + str r7, [sp, #S_IP] @ trace entry [IP = 0] + bl SYMBOL_NAME(syscall_trace) + str r7, [sp, #S_IP] + ldmia sp, {r0 - r3} @ have to reload r0 - r3 + adr ip, SYMBOL_NAME(sys_call_table) + str r4, [sp, #-4]! @ new style: (r0 = arg1, r5 = arg5) + mov lr, pc + ldr pc, [ip, r6, lsl #2] @ call sys routine + add sp, sp, #4 + str r0, [sp, #S_R0] @ returned r0 + mov r0, #1 + str r0, [sp, #S_IP] @ trace exit [IP = 1] + bl SYMBOL_NAME(syscall_trace) + str r7, [sp, #S_IP] + b ret_from_sys_call + +2: tst r6, #0x00f00000 @ is it a Unix SWI? + bne 3f + cmp r6, #(KSWI_SYS_BASE - KSWI_BASE) + bcc 4f @ not private func + bic r0, r6, #0x000f0000 + mov r1, sp + bl SYMBOL_NAME(arm_syscall) + b ret_from_sys_call + +3: eor r0, r6, #OS_NUMBER<<20 @ Put OS number back + mov r1, sp + bl SYMBOL_NAME(deferred) + ldmfd sp, {r0 - r3} + b ret_from_sys_call + +4: bl SYMBOL_NAME(sys_ni_syscall) + str r0, [sp, #0] @ returned r0 + b ret_from_sys_call + +@ r0 = syscall number +@ r1 = syscall r0 +@ r5 = syscall r4 +@ ip = syscall table +SYMBOL_NAME(sys_syscall): + mov r6, r0 + eor r6, r6, #OS_NUMBER << 20 + cmp r6, #NR_SYSCALLS @ check range + movgt r0, #-ENOSYS + movgt pc, lr + add sp, sp, #4 @ take of the save of our r4 + ldmib sp, {r0 - r4} @ get our args + str r4, [sp, #-4]! @ Put our arg on the stack + ldr pc, [ip, r6, lsl #2] + +ENTRY(sys_call_table) +#include "calls.S" + +/*============================================================================ + * Special system call wrappers + */ +sys_fork_wrapper: + add r0, sp, #4 + b SYMBOL_NAME(sys_fork) + +sys_execve_wrapper: + add r3, sp, #4 + b SYMBOL_NAME(sys_execve) + +sys_mount_wrapper: + mov r6, lr + add r5, sp, #4 + str r5, [sp] + str r4, [sp, #-4]! + bl SYMBOL_NAME(sys_compat_mount) + add sp, sp, #4 + RETINSTR(mov,pc,r6) + +sys_clone_wapper: + add r2, sp, #4 + b SYMBOL_NAME(sys_clone) + +sys_llseek_wrapper: + mov r6, lr + add r5, sp, #4 + str r5, [sp] + str r4, [sp, #-4]! + bl SYMBOL_NAME(sys_compat_llseek) + add sp, sp, #4 + RETINSTR(mov,pc,r6) + +sys_sigsuspend_wrapper: + add r3, sp, #4 + b SYMBOL_NAME(sys_sigsuspend) + +sys_rt_sigsuspend_wrapper: + add r2, sp, #4 + b SYMBOL_NAME(sys_rt_sigsuspend) + +sys_sigreturn_wrapper: + add r0, sp, #4 + b SYMBOL_NAME(sys_sigreturn) + +sys_rt_sigreturn_wrapper: + add r0, sp, #4 + b SYMBOL_NAME(sys_rt_sigreturn) + +/*============================================================================ + * All exits to user mode from the kernel go through this code. + */ + + .globl ret_from_sys_call + + .globl SYMBOL_NAME(fpreturn) +SYMBOL_NAME(fpreturn): +ret_from_exception: + adr r0, 1f + ldmia r0, {r0, r1} + ldr r0, [r0] + ldr r1, [r1] + tst r0, r1 + blne SYMBOL_NAME(do_bottom_half) +ret_from_intr: ldr r0, [sp, #S_PSR] + tst r0, #3 + beq ret_with_reschedule + b ret_from_all + +ret_signal: mov r1, sp + adrsvc al, lr, ret_from_all + b SYMBOL_NAME(do_signal) + +2: bl SYMBOL_NAME(schedule) + +ret_from_sys_call: + adr r0, 1f + ldmia r0, {r0, r1} + ldr r0, [r0] + ldr r1, [r1] + tst r0, r1 + adrsvc ne, lr, ret_from_intr + bne SYMBOL_NAME(do_bottom_half) + +ret_with_reschedule: + ldr r0, 1f + 8 + ldr r0, [r0] + teq r0, #0 + bne 2b + + get_current_task r1 + ldr r1, [r1, #SIGPENDING] + teq r1, #0 + bne ret_signal + +ret_from_all: restore_user_regs + +1: .word SYMBOL_NAME(bh_mask) + .word SYMBOL_NAME(bh_active) + .word SYMBOL_NAME(need_resched) + +/*============================================================================ + * FP support + */ + +1: .word SYMBOL_NAME(fp_save) + .word SYMBOL_NAME(fp_restore) + +.Lfpnull: mov pc, lr + + +/* + * Function to call when switching tasks to save FP state + */ +ENTRY(fpe_save) + ldr r1, 1b + ldr pc, [r1] + +/* + * Function to call when switching tasks to restore FP state + */ +ENTRY(fpe_restore) + ldr r1, 1b + 4 + ldr pc, [r1] + + + .data + +ENTRY(fp_enter) + .word SYMBOL_NAME(fpundefinstr) + .word SYMBOL_NAME(fpundefinstrsvc) + +ENTRY(fp_save) + .word .Lfpnull +ENTRY(fp_restore) + .word .Lfpnull + diff -ur --new-file old/linux/arch/arm/kernel/head-armo.S new/linux/arch/arm/kernel/head-armo.S --- old/linux/arch/arm/kernel/head-armo.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/head-armo.S Sat Feb 21 03:28:21 1998 @@ -0,0 +1,63 @@ +/* + * linux/arch/arm/kernel/head.S + * + * Copyright (C) 1994, 1995, 1996, 1997 Russell King + * + * 26-bit kernel startup code + */ +#include + + .text + .align +/* + * Entry point. + */ +ENTRY(stext) +ENTRY(_stext) +__entry: cmp pc, #0x02000000 + ldrlt pc, LC1 @ if 0x01800000, call at 0x02080000 + teq r0, #0 @ Check for old calling method + blne Loldparams @ Move page if old + adr r5, LC0 + ldmia r5, {r5, r6, sl, sp} @ Setup stack + mov r4, #0 +1: cmp r5, sl @ Clear BSS + strcc r4, [r5], #4 + bcc 1b + mov r0, #0xea000000 @ Point undef instr to continuation + adr r5, Lcontinue - 12 + orr r5, r0, r5, lsr #2 + str r5, [r4, #4] + mov r2, r4 + ldr r5, Larm2_id + swp r0, r0, [r2] @ check for swp (ARM2 can't) + ldr r5, Larm250_id + mrc 15, 0, r0, c0, c0 @ check for CP#15 (ARM250 can't) + mov r5, r0 @ Use processor ID if we do have CP#15 +Lcontinue: str r5, [r6] + mov r5, #0xeb000000 @ Point undef instr vector to itself + sub r5, r5, #2 + str r5, [r4, #4] + mov fp, #0 + b SYMBOL_NAME(start_kernel) + +LC1: .word SYMBOL_NAME(_stext) +LC0: .word SYMBOL_NAME(_edata) + .word SYMBOL_NAME(arm_id) + .word SYMBOL_NAME(_end) + .word SYMBOL_NAME(init_task_union)+8192 +Larm2_id: .long 0x41560200 +Larm250_id: .long 0x41560250 + .align + +Loldparams: mov r4, #0x02000000 + add r3, r4, #0x00080000 + add r4, r4, #0x0007c000 +1: ldmia r0!, {r5 - r12} + stmia r4!, {r5 - r12} + cmp r4, r3 + blt 1b + movs pc, lr + + .align 13 +ENTRY(this_must_match_init_task) diff -ur --new-file old/linux/arch/arm/kernel/head-armv.S new/linux/arch/arm/kernel/head-armv.S --- old/linux/arch/arm/kernel/head-armv.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/head-armv.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,312 @@ +/* + * linux/arch/arm/kernel/head32.S + * + * Copyright (C) 1994, 1995, 1996, 1997 Russell King + * + * Kernel 32 bit startup code for ARM6 / ARM7 / StrongARM + */ +#include +#include + .text + .align + + .globl SYMBOL_NAME(swapper_pg_dir) + .equ SYMBOL_NAME(swapper_pg_dir), 0xc0004000 + + .globl __stext +/* + * Entry point and restart point. Entry *must* be called with r0 == 0, + * MMU off. + * + * r1 = 0 -> ebsa (Ram @ 0x00000000) + * r1 = 1 -> RPC (Ram @ 0x10000000) + * r1 = 2 -> ebsit (???) + * r1 = 3 -> nexuspci + */ +ENTRY(stext) +ENTRY(_stext) +__entry: + teq r0, #0 @ check for illegal entry... + bne .Lerror @ loop indefinitely + cmp r1, #4 @ Unknown machine architecture + bge .Lerror +@ +@ First thing to do is to get the page tables set up so that we can call the kernel +@ in the correct place. This is relocatable code... +@ + mrc p15, 0, r9, c0, c0 @ get Processor ID +@ +@ Read processor ID register (CP#15, CR0). +@ NOTE: ARM2 & ARM250 cause an undefined instruction exception... +@ Values are: +@ XX01XXXX = ARMv4 architecture (StrongARM) +@ XX00XXXX = ARMv3 architecture +@ 4156061X = ARM 610 +@ 4156030X = ARM 3 +@ 4156025X = ARM 250 +@ 4156020X = ARM 2 +@ + adr r10, .LCProcTypes +1: ldmia r10!, {r5, r6, r8} @ Get Set, Mask, MMU Flags + teq r5, #0 @ End of list? + beq .Lerror + eor r5, r5, r9 + tst r5, r6 + addne r10, r10, #8 + bne 1b + + adr r4, .LCMachTypes + add r4, r4, r1, lsl #4 + ldmia r4, {r4, r5, r6} @ r4 = page dir in physical ram + + mov r0, r4 + mov r1, #0 + add r2, r0, #0x4000 +1: str r1, [r0], #4 @ Clear page table + teq r0, r2 + bne 1b +@ +@ Add enough entries to allow the kernel to be called. +@ It will sort out the real mapping in paging_init +@ + add r0, r4, #0x3000 + mov r1, #0x0000000c @ SECT_CACHEABLE | SECT_BUFFERABLE + orr r1, r1, r8 + add r1, r1, r5 + str r1, [r0], #4 + add r1, r1, #1 << 20 + str r1, [r0], #4 + add r1, r1, #1 << 20 +@ +@ Map in IO space +@ + add r0, r4, #0x3800 + orr r1, r6, r8 + add r2, r0, #0x0800 +1: str r1, [r0], #4 + add r1, r1, #1 << 20 + teq r0, r2 + bne 1b +@ +@ Map in screen at 0x02000000 & SCREEN2_BASE +@ + teq r5, #0 + addne r0, r4, #0x80 @ 02000000 + movne r1, #0x02000000 + orrne r1, r1, r8 + strne r1, [r0] + addne r0, r4, #0x3600 @ d8000000 + strne r1, [r0] +@ +@ The following should work on both v3 and v4 implementations +@ + mov lr, pc + mov pc, r10 @ Call processor flush (returns ctrl reg) + adr r5, __entry + sub r10, r10, r5 @ Make r10 PIC + ldr lr, .Lbranch + mcr p15, 0, r0, c1, c0 @ Enable MMU & caches. In 3 instructions + @ we lose this page! + mov pc, lr + +.Lerror: mov r0, #0x02000000 + mov r1, #0x11 + orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + str r1, [r0], #4 + str r1, [r0], #4 + str r1, [r0], #4 + str r1, [r0], #4 + b .Lerror + +.Lbranch: .long .Lalready_done_mmap @ Real address of routine + + @ EBSA (pg dir phys, phys ram start, phys i/o) +.LCMachTypes: .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 @ Address of page tables (physical) + .long 0 @ Address of RAM + .long 0xe0000000 @ I/O address + .long 0 + + @ RPC + .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x10000000 + .long 0x10000000 + .long 0x03000000 + .long 0 + + @ EBSIT ??? + .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + .long 0 + .long 0xe0000000 + .long 0 + + @ NexusPCI + .long SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0x40000000 + .long 0x40000000 + .long 0x10000000 + .long 0 + +.LCProcTypes: @ ARM6 / 610 + .long 0x41560600 + .long 0xffffff00 + .long 0x00000c12 + b .Larmv3_flush_early @ arm v3 flush & ctrl early setup + mov pc, lr + + @ ARM7 / 710 + .long 0x41007000 + .long 0xfffff000 + .long 0x00000c12 + b .Larmv3_flush_late @ arm v3 flush & ctrl late setup + mov pc, lr + + @ StrongARM + .long 0x4401a100 + .long 0xfffffff0 + .long 0x00000c02 + b .Larmv4_flush_early + b .Lsa_fastclock + + .long 0 + +.LC0: .long SYMBOL_NAME(_edata) + .long SYMBOL_NAME(arm_id) + .long SYMBOL_NAME(_end) + .long SYMBOL_NAME(init_task_union)+8192 + .align + +.Larmv3_flush_early: + mov r0, #0 + mcr p15, 0, r0, c7, c0 @ flush caches on v3 + mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mov r0, #0x3d @ ....S..DPWC.M + orr r0, r0, #0x100 + mov pc, lr + +.Larmv3_flush_late: + mov r0, #0 + mcr p15, 0, r0, c7, c0 @ flush caches on v3 + mcr p15, 0, r0, c5, c0 @ flush TLBs on v3 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mov r0, #0x7d @ ....S.LDPWC.M + orr r0, r0, #0x100 + mov pc, lr + +.Larmv4_flush_early: + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ flush I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ flush I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 + bic r0, r0, #0x0e00 + bic r0, r0, #0x0002 + orr r0, r0, #0x003d @ I...S..DPWC.M + orr r0, r0, #0x1100 @ v4 supports separate I cache + mov pc, lr + +.Lsa_fastclock: mcr p15, 0, r4, c15, c1, 2 @ Enable clock switching + mov pc, lr + +.Lalready_done_mmap: + adr r5, __entry @ Add base back in + add r10, r10, r5 + adr r5, .LC0 + ldmia r5, {r5, r6, r8, sp} @ Setup stack + mov r4, #0 +1: cmp r5, r8 @ Clear BSS + strcc r4, [r5],#4 + bcc 1b + + str r9, [r6] @ Save processor ID + mov lr, pc + add pc, r10, #4 @ Call post-processor init + mov fp, #0 + b SYMBOL_NAME(start_kernel) + +#if 1 +/* + * Useful debugging routines + */ + .globl _printhex8 +_printhex8: mov r1, #8 + b printhex + + .globl _printhex4 +_printhex4: mov r1, #4 + b printhex + + .globl _printhex2 +_printhex2: mov r1, #2 +printhex: ldr r2, =hexbuf + add r3, r2, r1 + mov r1, #0 + strb r1, [r3] +1: and r1, r0, #15 + mov r0, r0, lsr #4 + cmp r1, #10 + addlt r1, r1, #'0' + addge r1, r1, #'a' - 10 + strb r1, [r3, #-1]! + teq r3, r2 + bne 1b + mov r0, r2 + + .globl _printascii +_printascii: +#ifdef CONFIG_ARCH_RPC + mov r3, #0xe0000000 + orr r3, r3, #0x00010000 + orr r3, r3, #0x00000fe0 +#else + mov r3, #0xf0000000 + orr r3, r3, #0x0be0 +#endif + b 3f +1: ldrb r2, [r3, #0x18] + tst r2, #0x10 + beq 1b + strb r1, [r3] +2: ldrb r2, [r3, #0x14] + and r2, r2, #0x60 + teq r2, #0x60 + bne 2b + teq r1, #'\n' + moveq r1, #'\r' + beq 1b +3: teq r0, #0 + ldrneb r1, [r0], #1 + teqne r1, #0 + bne 1b + mov pc, lr + + .ltorg + + .globl _printch +_printch: +#ifdef CONFIG_ARCH_RPC + mov r3, #0xe0000000 + orr r3, r3, #0x00010000 + orr r3, r3, #0x00000fe0 +#else + mov r3, #0xf0000000 + orr r3, r3, #0x0be0 +#endif + mov r1, r0 + mov r0, #0 + b 1b + + .bss +hexbuf: .space 16 + +#endif + + .text + .align 13 +ENTRY(this_must_match_init_task) diff -ur --new-file old/linux/arch/arm/kernel/iic.c new/linux/arch/arm/kernel/iic.c --- old/linux/arch/arm/kernel/iic.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/iic.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,160 @@ +/* + * linux/arch/arm/kernel/iic.c + * + * Copyright (C) 1995, 1996 Russell King + * + * IIC is used to get the current time from the CMOS rtc. + */ + +#include +#include +#include +#include + +/* + * if delay loop has been calibrated then us that, + * else use IOC timer 1. + */ +static void iic_delay (void) +{ + extern unsigned long loops_per_sec; + if (loops_per_sec != (1 << 12)) { + udelay(10); + return; + } else { + unsigned long flags; + save_flags_cli(flags); + + outb(254, IOC_T1LTCHL); + outb(255, IOC_T1LTCHH); + outb(0, IOC_T1GO); + outb(1<<6, IOC_IRQCLRA); /* clear T1 irq */ + outb(4, IOC_T1LTCHL); + outb(0, IOC_T1LTCHH); + outb(0, IOC_T1GO); + while ((inb(IOC_IRQSTATA) & (1<<6)) == 0); + restore_flags(flags); + } +} + +static inline void iic_start (void) +{ + unsigned char out; + + out = inb(IOC_CONTROL) | 0xc2; + + outb(out, IOC_CONTROL); + iic_delay(); + + outb(out ^ 1, IOC_CONTROL); + iic_delay(); +} + +static inline void iic_stop (void) +{ + unsigned char out; + + out = inb(IOC_CONTROL) | 0xc3; + + iic_delay(); + outb(out ^ 1, IOC_CONTROL); + + iic_delay(); + outb(out, IOC_CONTROL); +} + +static int iic_sendbyte (unsigned char b) +{ + unsigned char out, in; + int i; + + out = (inb(IOC_CONTROL) & 0xfc) | 0xc0; + + outb(out, IOC_CONTROL); + for (i = 7; i >= 0; i--) { + unsigned char c; + c = out | ((b & (1 << i)) ? 1 : 0); + + outb(c, IOC_CONTROL); + iic_delay(); + + outb(c | 2, IOC_CONTROL); + iic_delay(); + + outb(c, IOC_CONTROL); + } + outb(out | 1, IOC_CONTROL); + iic_delay(); + + outb(out | 3, IOC_CONTROL); + iic_delay(); + + in = inb(IOC_CONTROL) & 1; + + outb(out | 1, IOC_CONTROL); + iic_delay(); + + outb(out, IOC_CONTROL); + iic_delay(); + + if(in) { + printk("No acknowledge from RTC\n"); + return 1; + } else + return 0; +} + +static unsigned char iic_recvbyte (void) +{ + unsigned char out, in; + int i; + + out = (inb(IOC_CONTROL) & 0xfc) | 0xc0; + + outb(out, IOC_CONTROL); + in = 0; + for (i = 7; i >= 0; i--) { + outb(out | 1, IOC_CONTROL); + iic_delay(); + outb(out | 3, IOC_CONTROL); + iic_delay(); + in = (in << 1) | (inb(IOC_CONTROL) & 1); + outb(out | 1, IOC_CONTROL); + iic_delay(); + } + outb(out, IOC_CONTROL); + iic_delay(); + outb(out | 2, IOC_CONTROL); + iic_delay(); + + return in; +} + +void iic_control (unsigned char addr, unsigned char loc, unsigned char *buf, int len) +{ + iic_start(); + + if (iic_sendbyte(addr & 0xfe)) + goto error; + + if (iic_sendbyte(loc)) + goto error; + + if (addr & 1) { + int i; + + for (i = 0; i < len; i++) + if (iic_sendbyte (buf[i])) + break; + } else { + int i; + + iic_stop(); + iic_start(); + iic_sendbyte(addr|1); + for (i = 0; i < len; i++) + buf[i] = iic_recvbyte (); + } +error: + iic_stop(); +} diff -ur --new-file old/linux/arch/arm/kernel/init_task.c new/linux/arch/arm/kernel/init_task.c --- old/linux/arch/arm/kernel/init_task.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/init_task.c Tue Mar 10 22:28:59 1998 @@ -0,0 +1,24 @@ +#include +#include + +#include +#include + +static struct vm_area_struct init_mmap = INIT_MMAP; +static struct fs_struct init_fs = INIT_FS; +static struct files * init_fd_array[NR_OPEN] = { NULL, }; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS; +struct mm_struct init_mm = INIT_MM; + +/* + * Initial task structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by making sure + * the linker maps this in the .text segment right after head.S, + * and making head.S ensure the proper alignment. + * + * The things we do for performance.. + */ +union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK }; diff -ur --new-file old/linux/arch/arm/kernel/ioport.c new/linux/arch/arm/kernel/ioport.c --- old/linux/arch/arm/kernel/ioport.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/ioport.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,98 @@ +/* + * linux/arch/arm/kernel/ioport.c + * + * This contains the io-permission bitmap code - written by obz, with changes + * by Linus. + * + * Modifications for ARM processor Copyright (C) 1995, 1996 Russell King + */ + +#include +#include +#include +#include +#include + +/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ +asmlinkage void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value) +{ + int mask; + unsigned long *bitmap_base = bitmap + (base >> 5); + unsigned short low_index = base & 0x1f; + int length = low_index + extent; + + if (low_index != 0) { + mask = (~0 << low_index); + if (length < 32) + mask &= ~(~0 << length); + if (new_value) + *bitmap_base++ |= mask; + else + *bitmap_base++ &= ~mask; + length -= 32; + } + + mask = (new_value ? ~0 : 0); + while (length >= 32) { + *bitmap_base++ = mask; + length -= 32; + } + + if (length > 0) { + mask = ~(~0 << length); + if (new_value) + *bitmap_base++ |= mask; + else + *bitmap_base++ &= ~mask; + } +} + +/* + * this changes the io permissions bitmap in the current task. + */ +asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) +{ + if (from + num <= from) + return -EINVAL; +#ifndef __arm__ + if (from + num > IO_BITMAP_SIZE*32) + return -EINVAL; +#endif + if (!suser()) + return -EPERM; + +#ifdef IODEBUG + printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off")); +#endif +#ifndef __arm__ + set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on); +#endif + return 0; +} + +unsigned int *stack; + +/* + * sys_iopl has to be used when you want to access the IO ports + * beyond the 0x3ff range: to get the full 65536 ports bitmapped + * you'd need 8kB of bitmaps/process, which is a bit excessive. + * + * Here we just change the eflags value on the stack: we allow + * only the super-user to do it. This depends on the stack-layout + * on system-call entry - see also fork() and the signal handling + * code. + */ +asmlinkage int sys_iopl(long ebx,long ecx,long edx, + long esi, long edi, long ebp, long eax, long ds, + long es, long fs, long gs, long orig_eax, + long eip,long cs,long eflags,long esp,long ss) +{ + unsigned int level = ebx; + + if (level > 3) + return -EINVAL; + if (!suser()) + return -EPERM; + *(&eflags) = (eflags & 0xffffcfff) | (level << 12); + return 0; +} diff -ur --new-file old/linux/arch/arm/kernel/irq.c new/linux/arch/arm/kernel/irq.c --- old/linux/arch/arm/kernel/irq.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/irq.c Sat Feb 21 03:28:21 1998 @@ -0,0 +1,327 @@ +/* + * linux/arch/arm/kernel/irq.c + * + * Copyright (C) 1992 Linus Torvalds + * Modifications for ARM processor Copyright (C) 1995, 1996 Russell King. + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + */ + +/* + * IRQ's are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ +#include /* for CONFIG_DEBUG_ERRORS */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +unsigned int local_irq_count[NR_CPUS]; +#ifdef __SMP__ +atomic_t __arm_bh_counter; +#else +int __arm_bh_counter; +#endif + +spinlock_t irq_controller_lock; + +#ifndef SMP +#define irq_enter(cpu, irq) (++local_irq_count[cpu]) +#define irq_exit(cpu, irq) (--local_irq_count[cpu]) +#else +#error SMP not supported +#endif + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + spin_lock_irqsave(&irq_controller_lock, flags); +#ifdef cliIF + save_flags(flags); + cliIF(); +#endif + mask_irq(irq_nr); + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + spin_lock_irqsave(&irq_controller_lock, flags); +#ifdef cliIF + save_flags (flags); + cliIF(); +#endif + unmask_irq(irq_nr); + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +struct irqaction *irq_action[NR_IRQS]; + +/* + * Bitmask indicating valid interrupt numbers + */ +unsigned long validirqs[NR_IRQS / 32] = { + 0x003fffff, 0x000001ff, 0x000000ff, 0x00000000 +}; + +int get_irq_list(char *buf) +{ + int i; + struct irqaction * action; + char *p = buf; + + for (i = 0 ; i < NR_IRQS ; i++) { + action = irq_action[i]; + if (!action) + continue; + p += sprintf(p, "%3d: %10u %s", + i, kstat.interrupts[i], action->name); + for (action = action->next; action; action = action->next) { + p += sprintf(p, ", %s", action->name); + } + *p++ = '\n'; + } + return p - buf; +} + +/* + * do_IRQ handles all normal device IRQ's + */ +asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +{ + struct irqaction * action; + int status, cpu; + +#if defined(HAS_IOMD) || defined(HAS_IOC) + if (irq != IRQ_EXPANSIONCARD) +#endif + { + spin_lock(&irq_controller_lock); + mask_and_ack_irq(irq); + spin_unlock(&irq_controller_lock); + } + + cpu = smp_processor_id(); + irq_enter(cpu, irq); + kstat.interrupts[irq]++; + + /* Return with this interrupt masked if no action */ + status = 0; + action = *(irq + irq_action); + if (action) { + if (!(action->flags & SA_INTERRUPT)) + __sti(); + + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + __cli(); +#if defined(HAS_IOMD) || defined(HAS_IOC) + if (irq != IRQ_KEYBOARDTX && irq != IRQ_EXPANSIONCARD) +#endif + { + spin_lock(&irq_controller_lock); + unmask_irq(irq); + spin_unlock(&irq_controller_lock); + } + } + + irq_exit(cpu, irq); + /* + * This should be conditional: we should really get + * a return code from the irq handler to tell us + * whether the handler wants us to do software bottom + * half handling or not.. + * + * ** IMPORTANT NOTE: do_bottom_half() ENABLES IRQS!!! ** + * ** WE MUST DISABLE THEM AGAIN, ELSE IDE DISKS GO ** + * ** AWOL ** + */ + if (1) { + if (bh_active & bh_mask) + do_bottom_half(); + __cli(); + } +} + +#if defined(HAS_IOMD) || defined(HAS_IOC) +void do_ecard_IRQ(int irq, struct pt_regs *regs) +{ + struct irqaction * action; + + action = *(irq + irq_action); + if (action) { + do { + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + } else { + spin_lock(&irq_controller_lock); + mask_irq (irq); + spin_unlock(&irq_controller_lock); + } +} +#endif + +int setup_arm_irq(int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + p = irq_action + irq; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + save_flags_cli(flags); + *p = new; + + if (!shared) { + spin_lock(&irq_controller_lock); + unmask_irq(irq); + spin_unlock(&irq_controller_lock); + } + restore_flags(flags); + return 0; +} + +/* + * Using "struct sigaction" is slightly silly, but there + * are historical reasons and it works well, so.. + */ +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long irq_flags, const char * devname, void *dev_id) +{ + unsigned long retval; + struct irqaction *action; + + if (irq >= NR_IRQS || !(validirqs[irq >> 5] & (1 << (irq & 31)))) + return -EINVAL; + if (!handler) + return -EINVAL; + + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irq_flags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_arm_irq(irq, action); + + if (retval) + kfree(action); + return retval; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction * action, **p; + unsigned long flags; + + if (irq >= NR_IRQS || !(validirqs[irq >> 5] & (1 << (irq & 31)))) { + printk(KERN_ERR "Trying to free IRQ%d\n",irq); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif + return; + } + for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + save_flags_cli (flags); + *p = action->next; + restore_flags (flags); + kfree(action); + return; + } + printk(KERN_ERR "Trying to free free IRQ%d\n",irq); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif +} + +unsigned long probe_irq_on (void) +{ + unsigned int i, irqs = 0; + unsigned long delay; + + /* first snaffle up any unassigned irqs */ + for (i = 15; i > 0; i--) { + if (!irq_action[i]) { + enable_irq(i); + irqs |= 1 << i; + } + } + + /* wait for spurious interrupts to mask themselves out again */ + for (delay = jiffies + HZ/10; delay > jiffies; ) + /* min 100ms delay */; + + /* now filter out any obviously spurious interrupts */ + return irqs & get_enabled_irqs(); +} + +int probe_irq_off (unsigned long irqs) +{ + unsigned int i; + + irqs &= ~get_enabled_irqs(); + if (!irqs) + return 0; + i = ffz (~irqs); + if (irqs != (irqs & (1 << i))) + i = -i; + return i; +} + +__initfunc(void init_IRQ(void)) +{ + irq_init_irq(); +} diff -ur --new-file old/linux/arch/arm/kernel/oldlatches.c new/linux/arch/arm/kernel/oldlatches.c --- old/linux/arch/arm/kernel/oldlatches.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/oldlatches.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,53 @@ +/* Support for the latches on the old Archimedes which control the floppy, + * hard disc and printer + * + * (c) David Alan Gilbert 1995/1996 + */ +#include + +#include +#include + +#ifdef LATCHAADDR +/* + * They are static so that everyone who accesses them has to go through here + */ +static unsigned char LatchACopy; + +/* newval=(oldval & ~mask)|newdata */ +void oldlatch_aupdate(unsigned char mask,unsigned char newdata) +{ + LatchACopy=(LatchACopy & ~mask)|newdata; + outb(LatchACopy, LATCHAADDR); +#ifdef DEBUG + printk("oldlatch_A:0x%2x\n",LatchACopy); +#endif + +} +#endif + +#ifdef LATCHBADDR +static unsigned char LatchBCopy; + +/* newval=(oldval & ~mask)|newdata */ +void oldlatch_bupdate(unsigned char mask,unsigned char newdata) +{ + LatchBCopy=(LatchBCopy & ~mask)|newdata; + outb(LatchBCopy, LATCHBADDR); +#ifdef DEBUG + printk("oldlatch_B:0x%2x\n",LatchBCopy); +#endif +} +#endif + +void oldlatch_init(void) +{ + printk("oldlatch: init\n"); +#ifdef LATCHAADDR + oldlatch_aupdate(0xff,0xff); +#endif +#ifdef LATCHBADDR + oldlatch_bupdate(0xff,0x8); /* Thats no FDC reset...*/ +#endif + return ; +} diff -ur --new-file old/linux/arch/arm/kernel/process.c new/linux/arch/arm/kernel/process.c --- old/linux/arch/arm/kernel/process.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/process.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,239 @@ +/* + * linux/arch/arm/kernel/process.c + * + * Copyright (C) 1996 Russell King - Converted to ARM. + * Origional Copyright (C) 1995 Linus Torvalds + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#define __KERNEL_SYSCALLS__ +#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 + +extern void fpe_save(struct fp_soft_struct *); +extern char *processor_modes[]; + +asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); + +static int hlt_counter=0; + +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + +/* + * The idle loop on an arm.. + */ +asmlinkage int sys_idle(void) +{ + int ret = -EPERM; + + lock_kernel(); + if (current->pid != 0) + goto out; + /* endless idle loop with no priority at all */ + current->priority = -100; + for (;;) + { + if (!hlt_counter && !need_resched) + proc_idle (); + run_task_queue(&tq_scheduler); + schedule(); + } + ret = 0; +out: + unlock_kernel(); + return ret; +} + +__initfunc(void reboot_setup(char *str, int *ints)) +{ +} + +/* + * This routine reboots the machine by resetting the expansion cards via + * their loaders, turning off the processor cache (if ARM3), copying the + * first instruction of the ROM to 0, and executing it there. + */ +void machine_restart(char * __unused) +{ + proc_hard_reset (); + arch_hard_reset (); +} + +void machine_halt(void) +{ +} + +void machine_power_off(void) +{ +} + + +void show_regs(struct pt_regs * regs) +{ + unsigned long flags; + + flags = condition_codes(regs); + + printk("\n" + "pc : [<%08lx>]\n" + "lr : [<%08lx>]\n" + "sp : %08lx ip : %08lx fp : %08lx\n", + instruction_pointer(regs), + regs->ARM_lr, regs->ARM_sp, + regs->ARM_ip, regs->ARM_fp); + printk( "r10: %08lx r9 : %08lx r8 : %08lx\n", + regs->ARM_r10, regs->ARM_r9, + regs->ARM_r8); + printk( "r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", + regs->ARM_r7, regs->ARM_r6, + regs->ARM_r5, regs->ARM_r4); + printk( "r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", + regs->ARM_r3, regs->ARM_r2, + regs->ARM_r1, regs->ARM_r0); + printk("Flags: %c%c%c%c", + flags & CC_N_BIT ? 'N' : 'n', + flags & CC_Z_BIT ? 'Z' : 'z', + flags & CC_C_BIT ? 'C' : 'c', + flags & CC_V_BIT ? 'V' : 'v'); + printk(" IRQs %s FIQs %s Mode %s\n", + interrupts_enabled(regs) ? "on" : "off", + fast_interrupts_enabled(regs) ? "on" : "off", + processor_modes[processor_mode(regs)]); +#if defined(CONFIG_CPU_ARM6) || defined(CONFIG_CPU_SA110) +{ int ctrl, transbase, dac; + __asm__ ( +" mrc p15, 0, %0, c1, c0\n" +" mrc p15, 0, %1, c2, c0\n" +" mrc p15, 0, %2, c3, c0\n" + : "=r" (ctrl), "=r" (transbase), "=r" (dac)); + printk("Control: %04X Table: %08X DAC: %08X", + ctrl, transbase, dac); + } +#endif + printk ("Segment %s\n", get_fs() == get_ds() ? "kernel" : "user"); +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ + if (last_task_used_math == current) + last_task_used_math = NULL; +} + +void flush_thread(void) +{ + int i; + + for (i = 0; i < 8; i++) + current->debugreg[i] = 0; + if (last_task_used_math == current) + last_task_used_math = NULL; + current->used_math = 0; + current->flags &= ~PF_USEDFPU; +} + +void release_thread(struct task_struct *dead_task) +{ +} + +int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + struct context_save_struct * save; + + childregs = ((struct pt_regs *)((unsigned long)p + 8192)) - 1; + *childregs = *regs; + childregs->ARM_r0 = 0; + + save = ((struct context_save_struct *)(childregs)) - 1; + copy_thread_css (save); + p->tss.save = save; + /* + * Save current math state in p->tss.fpe_save if not already there. + */ + if (last_task_used_math == current) + fpe_save (&p->tss.fpstate.soft); + + return 0; +} + +/* + * fill in the fpe structure for a core dump... + */ +int dump_fpu (struct pt_regs *regs, struct user_fp *fp) +{ + int fpvalid = 0; + + if (current->used_math) { + if (last_task_used_math == current) + fpe_save (¤t->tss.fpstate.soft); + + memcpy (fp, ¤t->tss.fpstate.soft, sizeof (fp)); + } + + return fpvalid; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + int i; + + dump->magic = CMAGIC; + dump->start_code = current->mm->start_code; + dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1); + + dump->u_tsize = (current->mm->end_code - current->mm->start_code) >> PAGE_SHIFT; + dump->u_dsize = (current->mm->brk - current->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT; + dump->u_ssize = 0; + + for (i = 0; i < 8; i++) + dump->u_debugreg[i] = current->debugreg[i]; + + if (dump->start_stack < 0x04000000) + dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT; + + dump->regs = *regs; + dump->u_fpvalid = dump_fpu (regs, &dump->u_fp); +} diff -ur --new-file old/linux/arch/arm/kernel/ptrace.c new/linux/arch/arm/kernel/ptrace.c --- old/linux/arch/arm/kernel/ptrace.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/ptrace.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,745 @@ +/* ptrace.c */ +/* By Ross Biro 1/23/92 */ +/* edited by Linus Torvalds */ +/* edited for ARM by Russell King */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* + * Breakpoint SWI instruction: SWI &9F0001 + */ +#define BREAKINST 0xef9f0001 + +/* change a pid into a task struct. */ +static inline struct task_struct * get_task(int pid) +{ + int i; + + for (i = 1; i < NR_TASKS; i++) { + if (task[i] != NULL && (task[i]->pid == pid)) + return task[i]; + } + return NULL; +} + +/* + * this routine will get a word off of the processes privileged stack. + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the privileged stacks are in our + * data space. + */ +static inline long get_stack_long(struct task_struct *task, int offset) +{ + unsigned char *stack; + + stack = (unsigned char *)((unsigned long)task + 8192 - sizeof(struct pt_regs)); + stack += offset << 2; + return *(unsigned long *)stack; +} + +/* + * this routine will put a word on the processes privileged stack. + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the privileged stacks are in our + * data space. + */ +static inline long put_stack_long(struct task_struct *task, int offset, + unsigned long data) +{ + unsigned char *stack; + + stack = (unsigned char *)((unsigned long)task + 8192 - sizeof(struct pt_regs)); + stack += offset << 2; + *(unsigned long *) stack = data; + return 0; +} + +/* + * This routine gets a long from any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + */ +static unsigned long get_long(struct task_struct * tsk, + struct vm_area_struct * vma, unsigned long addr) +{ + pgd_t *pgdir; + pmd_t *pgmiddle; + pte_t *pgtable; + unsigned long page; + +repeat: + pgdir = pgd_offset(vma->vm_mm, addr); + if (pgd_none(*pgdir)) { + handle_mm_fault(tsk, vma, addr, 0); + goto repeat; + } + if (pgd_bad(*pgdir)) { + printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); + return 0; + } + pgmiddle = pmd_offset(pgdir, addr); + if (pmd_none(*pgmiddle)) { + handle_mm_fault(tsk, vma, addr, 0); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return 0; + } + pgtable = pte_offset(pgmiddle, addr); + if (!pte_present(*pgtable)) { + handle_mm_fault(tsk, vma, addr, 0); + goto repeat; + } + page = pte_page(*pgtable); + + if(MAP_NR(page) >= max_mapnr) + return 0; + page += addr & ~PAGE_MASK; + return *(unsigned long *)page; +} + +/* + * This routine puts a long into any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + * + * Now keeps R/W state of the page so that a text page stays readonly + * even if a debugger scribbles breakpoints into it. -M.U- + */ +static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr, + unsigned long data) +{ + pgd_t *pgdir; + pmd_t *pgmiddle; + pte_t *pgtable; + unsigned long page; + +repeat: + pgdir = pgd_offset(vma->vm_mm, addr); + if (!pgd_present(*pgdir)) { + handle_mm_fault(tsk, vma, addr, 1); + goto repeat; + } + if (pgd_bad(*pgdir)) { + printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); + return; + } + pgmiddle = pmd_offset(pgdir, addr); + if (pmd_none(*pgmiddle)) { + handle_mm_fault(tsk, vma, addr, 1); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return; + } + pgtable = pte_offset(pgmiddle, addr); + if (!pte_present(*pgtable)) { + handle_mm_fault(tsk, vma, addr, 1); + goto repeat; + } + page = pte_page(*pgtable); + if (!pte_write(*pgtable)) { + handle_mm_fault(tsk, vma, addr, 1); + goto repeat; + } + + if (MAP_NR(page) < max_mapnr) { + page += addr & ~PAGE_MASK; + *(unsigned long *)page = data; + __flush_entry_to_ram(page); + } + set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + flush_tlb(); +} + +static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr) +{ + struct vm_area_struct * vma; + + addr &= PAGE_MASK; + vma = find_vma(tsk->mm,addr); + if (!vma) + return NULL; + if (vma->vm_start <= addr) + return vma; + if (!(vma->vm_flags & VM_GROWSDOWN)) + return NULL; + if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur) + return NULL; + vma->vm_offset -= vma->vm_start - addr; + vma->vm_start = addr; + return vma; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls get_long() to read a long. + */ +static int read_long(struct task_struct * tsk, unsigned long addr, + unsigned long * result) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { + unsigned long low,high; + struct vm_area_struct * vma_high = vma; + + if (addr + sizeof(long) >= vma->vm_end) { + vma_high = vma->vm_next; + if (!vma_high || vma_high->vm_start != vma->vm_end) + return -EIO; + } + low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); + high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 1: + low >>= 8; + low |= high << 24; + break; + case 2: + low >>= 16; + low |= high << 16; + break; + case 3: + low >>= 24; + low |= high << 8; + break; + } + *result = low; + } else + *result = get_long(tsk, vma, addr); + return 0; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls put_long() to write a long. + */ +static int write_long(struct task_struct * tsk, unsigned long addr, + unsigned long data) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { + unsigned long low,high; + struct vm_area_struct * vma_high = vma; + + if (addr + sizeof(long) >= vma->vm_end) { + vma_high = vma->vm_next; + if (!vma_high || vma_high->vm_start != vma->vm_end) + return -EIO; + } + low = get_long(tsk, vma, addr & ~(sizeof(long)-1)); + high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 0: /* shouldn't happen, but safety first */ + low = data; + break; + case 1: + low &= 0x000000ff; + low |= data << 8; + high &= ~0xff; + high |= data >> 24; + break; + case 2: + low &= 0x0000ffff; + low |= data << 16; + high &= ~0xffff; + high |= data >> 16; + break; + case 3: + low &= 0x00ffffff; + low |= data << 24; + high &= ~0xffffff; + high |= data >> 8; + break; + } + put_long(tsk, vma, addr & ~(sizeof(long)-1),low); + put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high); + } else + put_long(tsk, vma, addr, data); + return 0; +} + +/* + * Get value of register `rn' (in the instruction) + */ +static unsigned long ptrace_getrn (struct task_struct *child, unsigned long insn) +{ + unsigned int reg = (insn >> 16) & 15; + unsigned long val; + + if (reg == 15) + val = pc_pointer (get_stack_long (child, reg)); + else + val = get_stack_long (child, reg); + +printk ("r%02d=%08lX ", reg, val); + return val; +} + +/* + * Get value of operand 2 (in an ALU instruction) + */ +static unsigned long ptrace_getaluop2 (struct task_struct *child, unsigned long insn) +{ + unsigned long val; + int shift; + int type; + +printk ("op2="); + if (insn & 1 << 25) { + val = insn & 255; + shift = (insn >> 8) & 15; + type = 3; +printk ("(imm)"); + } else { + val = get_stack_long (child, insn & 15); + + if (insn & (1 << 4)) + shift = (int)get_stack_long (child, (insn >> 8) & 15); + else + shift = (insn >> 7) & 31; + + type = (insn >> 5) & 3; +printk ("(r%02ld)", insn & 15); + } +printk ("sh%dx%d", type, shift); + switch (type) { + case 0: val <<= shift; break; + case 1: val >>= shift; break; + case 2: + val = (((signed long)val) >> shift); + break; + case 3: + __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift)); + break; + } +printk ("=%08lX ", val); + return val; +} + +/* + * Get value of operand 2 (in a LDR instruction) + */ +static unsigned long ptrace_getldrop2 (struct task_struct *child, unsigned long insn) +{ + unsigned long val; + int shift; + int type; + + val = get_stack_long (child, insn & 15); + shift = (insn >> 7) & 31; + type = (insn >> 5) & 3; + +printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type); + switch (type) { + case 0: val <<= shift; break; + case 1: val >>= shift; break; + case 2: + val = (((signed long)val) >> shift); + break; + case 3: + __asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift)); + break; + } +printk ("=%08lX ", val); + return val; +} +#undef pc_pointer +#define pc_pointer(x) ((x) & 0x03fffffc) +int ptrace_set_bpt (struct task_struct *child) +{ + unsigned long insn, pc, alt; + int i, nsaved = 0, res; + + pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/)); + + res = read_long (child, pc, &insn); + if (res < 0) + return res; + + child->debugreg[nsaved++] = alt = pc + 4; +printk ("ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc); + switch (insn & 0x0e100000) { + case 0x00000000: + case 0x00100000: + case 0x02000000: + case 0x02100000: /* data processing */ + printk ("data "); + switch (insn & 0x01e0f000) { + case 0x0000f000: + alt = ptrace_getrn(child, insn) & ptrace_getaluop2(child, insn); + break; + case 0x0020f000: + alt = ptrace_getrn(child, insn) ^ ptrace_getaluop2(child, insn); + break; + case 0x0040f000: + alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn); + break; + case 0x0060f000: + alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn); + break; + case 0x0080f000: + alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn); + break; + case 0x00a0f000: + alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn) + + (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); + break; + case 0x00c0f000: + alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn) + + (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); + break; + case 0x00e0f000: + alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn) + + (get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0); + break; + case 0x0180f000: + alt = ptrace_getrn(child, insn) | ptrace_getaluop2(child, insn); + break; + case 0x01a0f000: + alt = ptrace_getaluop2(child, insn); + break; + case 0x01c0f000: + alt = ptrace_getrn(child, insn) & ~ptrace_getaluop2(child, insn); + break; + case 0x01e0f000: + alt = ~ptrace_getaluop2(child, insn); + break; + } + break; + + case 0x04100000: /* ldr */ + if ((insn & 0xf000) == 0xf000) { +printk ("ldr "); + alt = ptrace_getrn(child, insn); + if (insn & 1 << 24) { + if (insn & 1 << 23) + alt += ptrace_getldrop2 (child, insn); + else + alt -= ptrace_getldrop2 (child, insn); + } + if (read_long (child, alt, &alt) < 0) + alt = pc + 4; /* not valid */ + else + alt = pc_pointer (alt); + } + break; + + case 0x06100000: /* ldr imm */ + if ((insn & 0xf000) == 0xf000) { +printk ("ldrimm "); + alt = ptrace_getrn(child, insn); + if (insn & 1 << 24) { + if (insn & 1 << 23) + alt += insn & 0xfff; + else + alt -= insn & 0xfff; + } + if (read_long (child, alt, &alt) < 0) + alt = pc + 4; /* not valid */ + else + alt = pc_pointer (alt); + } + break; + + case 0x08100000: /* ldm */ + if (insn & (1 << 15)) { + unsigned long base; + int nr_regs; +printk ("ldm "); + + if (insn & (1 << 23)) { + nr_regs = insn & 65535; + + nr_regs = (nr_regs & 0x5555) + ((nr_regs & 0xaaaa) >> 1); + nr_regs = (nr_regs & 0x3333) + ((nr_regs & 0xcccc) >> 2); + nr_regs = (nr_regs & 0x0707) + ((nr_regs & 0x7070) >> 4); + nr_regs = (nr_regs & 0x000f) + ((nr_regs & 0x0f00) >> 8); + nr_regs <<= 2; + + if (!(insn & (1 << 24))) + nr_regs -= 4; + } else { + if (insn & (1 << 24)) + nr_regs = -4; + else + nr_regs = 0; + } + + base = ptrace_getrn (child, insn); + + if (read_long (child, base + nr_regs, &alt) < 0) + alt = pc + 4; /* not valid */ + else + alt = pc_pointer (alt); + break; + } + break; + + case 0x0a000000: + case 0x0a100000: { /* bl or b */ + signed long displ; +printk ("b/bl "); + /* It's a branch/branch link: instead of trying to + * figure out whether the branch will be taken or not, + * we'll put a breakpoint at either location. This is + * simpler, more reliable, and probably not a whole lot + * slower than the alternative approach of emulating the + * branch. + */ + displ = (insn & 0x00ffffff) << 8; + displ = (displ >> 6) + 8; + if (displ != 0 && displ != 4) + alt = pc + displ; + } + break; + } +printk ("=%08lX\n", alt); + if (alt != pc + 4) + child->debugreg[nsaved++] = alt; + + for (i = 0; i < nsaved; i++) { + res = read_long (child, child->debugreg[i], &insn); + if (res >= 0) { + child->debugreg[i + 2] = insn; + res = write_long (child, child->debugreg[i], BREAKINST); + } + if (res < 0) { + child->debugreg[4] = 0; + return res; + } + } + child->debugreg[4] = nsaved; + return 0; +} + +/* Ensure no single-step breakpoint is pending. Returns non-zero + * value if child was being single-stepped. + */ +int ptrace_cancel_bpt (struct task_struct *child) +{ + int i, nsaved = child->debugreg[4]; + + child->debugreg[4] = 0; + + if (nsaved > 2) { + printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); + nsaved = 2; + } + for (i = 0; i < nsaved; i++) + write_long (child, child->debugreg[i], child->debugreg[i + 2]); + return nsaved != 0; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->flags & PF_PTRACED) + goto out; + /* set the ptrace bit in the process flags. */ + current->flags |= PF_PTRACED; + ret = 0; + goto out; + } + if (pid == 1) /* you may not mess with init */ + goto out; + ret = -ESRCH; + if (!(child = get_task(pid))) + goto out; + ret = -EPERM; + if (request == PTRACE_ATTACH) { + if (child == current) + goto out; + if ((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->suid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->sgid) || + (current->gid != child->gid)) && !suser()) + 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) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + send_sig(SIGSTOP, child, 1); + ret = 0; + goto out; + } + ret = -ESRCH; + if (!(child->flags & PF_PTRACED)) + goto out; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out; + } + if (child->p_pptr != current) + goto out; + + switch (request) { + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + + ret = read_long(child, addr, &tmp); + if (ret >= 0) + ret = put_user(tmp, (unsigned long *)data); + goto out; + } + + case PTRACE_PEEKUSR: { /* read the word at location addr in the USER area. */ + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) + goto out; + + tmp = 0; /* Default return condition */ + if (addr < sizeof (struct pt_regs)) + tmp = get_stack_long(child, (int)addr >> 2); + ret = put_user(tmp, (unsigned long *)data); + goto out; + } + + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + ret = write_long(child,addr,data); + goto out; + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) + goto out; + + if (addr < sizeof (struct pt_regs)) + ret = put_stack_long(child, (int)addr >> 2, data); + goto out; + + case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ + case PTRACE_CONT: /* restart after signal. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out; + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; + wake_up_process (child); + /* make sure single-step breakpoint is gone. */ + ptrace_cancel_bpt (child); + ret = 0; + goto out; + + /* make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: + if (child->state == TASK_ZOMBIE) /* already dead */ + return 0; + wake_up_process (child); + child->exit_code = SIGKILL; + ptrace_cancel_bpt (child); + /* make sure single-step breakpoint is gone. */ + ptrace_cancel_bpt (child); + ret = 0; + goto out; + + case PTRACE_SINGLESTEP: /* execute single instruction. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out; + child->debugreg[4] = -1; + child->flags &= ~PF_TRACESYS; + wake_up_process(child); + child->exit_code = data; + /* give it a chance to run. */ + ret = 0; + goto out; + + case PTRACE_DETACH: /* detach a process that was attached. */ + ret = -EIO; + if ((unsigned long) data > _NSIG) + goto out; + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + wake_up_process (child); + child->exit_code = data; + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + /* make sure single-step breakpoint is gone. */ + ptrace_cancel_bpt (child); + ret = 0; + goto out; + + default: + ret = -EIO; + goto out; + } +out: + unlock_kernel(); + return ret; +} + +asmlinkage void syscall_trace(void) +{ + if ((current->flags & (PF_PTRACED|PF_TRACESYS)) + != (PF_PTRACED|PF_TRACESYS)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} diff -ur --new-file old/linux/arch/arm/kernel/setup-ebsa110.c new/linux/arch/arm/kernel/setup-ebsa110.c --- old/linux/arch/arm/kernel/setup-ebsa110.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/setup-ebsa110.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,143 @@ +/* + * linux/arch/arm/kernel/setup-sa.c + * + * Copyright (C) 1995, 1996 Russell King + */ + +/* + * This file obtains various parameters about the system that the kernel + * is running on. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef CONFIG_CMDLINE +#define CONFIG_CMDLINE "root=nfs rw console=ttyS1,38400n8" +#endif +#define MEM_SIZE (16*1024*1024) + +#define COMMAND_LINE_SIZE 256 + +unsigned char aux_device_present; +unsigned long arm_id; +extern int root_mountflags; +extern int _etext, _edata, _end; + +#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 */ + +static inline void setup_ramdisk (void) +{ + rd_image_start = 0; + rd_prompt = 1; + rd_doload = 1; +} +#else +#define setup_ramdisk() +#endif + +static char default_command_line[] = CONFIG_CMDLINE; +static char command_line[COMMAND_LINE_SIZE] = { 0, }; + char saved_command_line[COMMAND_LINE_SIZE]; + +struct processor processor; +extern const struct processor sa110_processor_functions; + +void setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p) +{ + unsigned long memory_start, memory_end; + char c = ' ', *to = command_line, *from; + int len = 0; + + memory_start = (unsigned long)&_end; + memory_end = 0xc0000000 + MEM_SIZE; + from = default_command_line; + + processor = sa110_processor_functions; + processor._proc_init (); + + ROOT_DEV = 0x00ff; + setup_ramdisk(); + + init_task.mm->start_code = TASK_SIZE; + init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext; + init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata; + init_task.mm->brk = TASK_SIZE + (unsigned long) &_end; + + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, from, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + + for (;;) { + if (c == ' ' && + from[0] == 'm' && + from[1] == 'e' && + from[2] == 'm' && + from[3] == '=') { + memory_end = simple_strtoul(from+4, &from, 0); + if ( *from == 'K' || *from == 'k' ) { + memory_end = memory_end << 10; + from++; + } else if ( *from == 'M' || *from == 'm' ) { + memory_end = memory_end << 20; + from++; + } + memory_end = memory_end + PAGE_OFFSET; + } + c = *from++; + if (!c) + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *to++ = c; + } + + *to = '\0'; + *cmdline_p = command_line; + *memory_start_p = memory_start; + *memory_end_p = memory_end; + strcpy (system_utsname.machine, "sa110"); +} + +int get_cpuinfo(char * buffer) +{ + int len; + + len = sprintf (buffer, "CPU:\n" + "Type\t\t: %s\n" + "Revision\t: %d\n" + "Manufacturer\t: %s\n" + "32bit modes\t: %s\n" + "BogoMips\t: %lu.%02lu\n", + "sa110", + (int)arm_id & 15, + "DEC", + "yes", + (loops_per_sec+2500) / 500000, + ((loops_per_sec+2500) / 5000) % 100); + return len; +} diff -ur --new-file old/linux/arch/arm/kernel/setup.c new/linux/arch/arm/kernel/setup.c --- old/linux/arch/arm/kernel/setup.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/setup.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,292 @@ +/* + * linux/arch/arm/kernel/setup.c + * + * Copyright (C) 1995, 1996, 1997 Russell King + */ + +/* + * This file obtains various parameters about the system that the kernel + * is running on. + */ + +#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 + +struct drive_info_struct { char dummy[32]; } drive_info; +struct screen_info screen_info; +struct processor processor; +unsigned char aux_device_present; + +extern const struct processor arm2_processor_functions; +extern const struct processor arm250_processor_functions; +extern const struct processor arm3_processor_functions; +extern const struct processor arm6_processor_functions; +extern const struct processor arm7_processor_functions; +extern const struct processor sa110_processor_functions; + +struct armversions armidlist[] = { +#if defined(CONFIG_CPU_ARM2) || defined(CONFIG_CPU_ARM3) + { 0x41560200, 0xfffffff0, F_MEMC , "ARM/VLSI", "arm2" , &arm2_processor_functions }, + { 0x41560250, 0xfffffff0, F_MEMC , "ARM/VLSI", "arm250" , &arm250_processor_functions }, + { 0x41560300, 0xfffffff0, F_MEMC|F_CACHE, "ARM/VLSI", "arm3" , &arm3_processor_functions }, +#endif +#if defined(CONFIG_CPU_ARM6) || defined(CONFIG_CPU_SA110) + { 0x41560600, 0xfffffff0, F_MMU|F_32BIT , "ARM/VLSI", "arm6" , &arm6_processor_functions }, + { 0x41560610, 0xfffffff0, F_MMU|F_32BIT , "ARM/VLSI", "arm610" , &arm6_processor_functions }, + { 0x41007000, 0xffffff00, F_MMU|F_32BIT , "ARM/VLSI", "arm7" , &arm7_processor_functions }, + { 0x41007100, 0xffffff00, F_MMU|F_32BIT , "ARM/VLSI", "arm710" , &arm7_processor_functions }, + { 0x4401a100, 0xfffffff0, F_MMU|F_32BIT , "DEC", "sa110" , &sa110_processor_functions }, +#endif + { 0x00000000, 0x00000000, 0 , "***", "*unknown*" , NULL } +}; + +static struct param_struct *params = (struct param_struct *)PARAMS_BASE; + +unsigned long arm_id; +unsigned int vram_half_sam; +int armidindex; +int ioebpresent; +int memc_ctrl_reg; +int number_ide_drives; +int number_mfm_drives; + +extern int bytes_per_char_h; +extern int bytes_per_char_v; +extern int root_mountflags; +extern int _etext, _edata, _end; +extern unsigned long real_end_mem; + +/*------------------------------------------------------------------------- + * Early initialisation routines for various configurable items in the + * kernel. Each one either supplies a setup_ function, or defines this + * symbol to be empty if not configured. + */ + +/* + * Risc-PC specific initialisation + */ +#ifdef CONFIG_ARCH_RPC + +extern void init_dram_banks(struct param_struct *params); + +static void setup_rpc (struct param_struct *params) +{ + init_dram_banks(params); + + switch (params->u1.s.pages_in_vram) { + case 256: + vram_half_sam = 1024; + break; + case 512: + default: + vram_half_sam = 2048; + } + + /* + * Set ROM speed to maximum + */ + outb (0x1d, IOMD_ROMCR0); +} +#else +#define setup_rpc(x) +#endif + +/* + * ram disk + */ +#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 */ + +static void setup_ramdisk (struct param_struct *params) +{ + rd_image_start = params->u1.s.rd_start; + rd_prompt = (params->u1.s.flags & FLAG_RDPROMPT) == 0; + rd_doload = (params->u1.s.flags & FLAG_RDLOAD) == 0; +} +#else +#define setup_ramdisk(p) +#endif + +/* + * initial ram disk + */ +#ifdef CONFIG_BLK_DEV_INITRD +static void setup_initrd (struct param_struct *params, unsigned long memory_end) +{ + initrd_start = params->u1.s.initrd_start; + initrd_end = params->u1.s.initrd_start + params->u1.s.initrd_size; + + if (initrd_end > memory_end) { + printk ("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx) - disabling initrd\n", + initrd_end, memory_end); + initrd_start = 0; + } +} +#else +#define setup_initrd(p,m) +#endif + +static inline void check_ioeb_present(void) +{ + if (((*IOEB_BASE) & 15) == 5) + armidlist[armidindex].features |= F_IOEB; +} + +static void get_processor_type (void) +{ + for (armidindex = 0; ; armidindex ++) + if (!((armidlist[armidindex].id ^ arm_id) & + armidlist[armidindex].mask)) + break; + + if (armidlist[armidindex].id == 0) { + int i; + + for (i = 0; i < 3200; i++) + ((unsigned long *)SCREEN2_BASE)[i] = 0x77113322; + + while (1); + } + processor = *armidlist[armidindex].proc; +} + +#define COMMAND_LINE_SIZE 256 + +static char command_line[COMMAND_LINE_SIZE] = { 0, }; + char saved_command_line[COMMAND_LINE_SIZE]; + +void setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p) +{ + static unsigned char smptrap; + unsigned long memory_start, memory_end; + char c = ' ', *to = command_line, *from; + int len = 0; + + if (smptrap == 1) + return; + smptrap = 1; + + get_processor_type (); + check_ioeb_present (); + processor._proc_init (); + + bytes_per_char_h = params->u1.s.bytes_per_char_h; + bytes_per_char_v = params->u1.s.bytes_per_char_v; + from = params->commandline; + ROOT_DEV = to_kdev_t (params->u1.s.rootdev); + ORIG_X = params->u1.s.video_x; + ORIG_Y = params->u1.s.video_y; + ORIG_VIDEO_COLS = params->u1.s.video_num_cols; + ORIG_VIDEO_LINES = params->u1.s.video_num_rows; + memc_ctrl_reg = params->u1.s.memc_control_reg; + number_ide_drives = (params->u1.s.adfsdrives >> 6) & 3; + number_mfm_drives = (params->u1.s.adfsdrives >> 3) & 3; + + setup_rpc (params); + setup_ramdisk (params); + + if (!(params->u1.s.flags & FLAG_READONLY)) + root_mountflags &= ~MS_RDONLY; + + memory_start = MAPTOPHYS((unsigned long)&_end); + memory_end = GET_MEMORY_END(params); + + init_task.mm->start_code = TASK_SIZE; + init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext; + init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata; + init_task.mm->brk = TASK_SIZE + (unsigned long) &_end; + + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, from, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + + for (;;) { + if (c == ' ' && + from[0] == 'm' && + from[1] == 'e' && + from[2] == 'm' && + from[3] == '=') { + memory_end = simple_strtoul(from+4, &from, 0); + if (*from == 'K' || *from == 'k') { + memory_end = memory_end << 10; + from++; + } else if (*from == 'M' || *from == 'm') { + memory_end = memory_end << 20; + from++; + } + memory_end = memory_end + PAGE_OFFSET; + } + c = *from++; + if (!c) + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *to++ = c; + } + + *to = '\0'; + *cmdline_p = command_line; + *memory_start_p = memory_start; + *memory_end_p = memory_end; + + setup_initrd (params, memory_end); + + strcpy (system_utsname.machine, armidlist[armidindex].name); +} + +#define ISSET(bit) (armidlist[armidindex].features & bit) + +int get_cpuinfo(char * buffer) +{ + int len; + + len = sprintf (buffer, "CPU:\n" + "Type\t\t: %s\n" + "Revision\t: %d\n" + "Manufacturer\t: %s\n" + "32bit modes\t: %s\n" + "BogoMips\t: %lu.%02lu\n", + armidlist[armidindex].name, + (int)arm_id & 15, + armidlist[armidindex].manu, + ISSET (F_32BIT) ? "yes" : "no", + (loops_per_sec+2500) / 500000, + ((loops_per_sec+2500) / 5000) % 100); + len += sprintf (buffer + len, + "\nHardware:\n" + "Mem System\t: %s\n" + "IOEB\t\t: %s\n", + ISSET(F_MEMC) ? "MEMC" : + ISSET(F_MMU) ? "MMU" : "*unknown*", + ISSET(F_IOEB) ? "present" : "absent" + ); + return len; +} diff -ur --new-file old/linux/arch/arm/kernel/signal.c new/linux/arch/arm/kernel/signal.c --- old/linux/arch/arm/kernel/signal.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/signal.c Sat Feb 21 03:28:21 1998 @@ -0,0 +1,515 @@ +/* + * linux/arch/arm/kernel/signal.c + * + * Copyright (C) 1995, 1996 Russell King + */ + +#include /* for CONFIG_CPU_ARM6 and CONFIG_CPU_SA110 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)) +#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)) + +asmlinkage int sys_wait4(pid_t pid, unsigned long * stat_addr, + int options, unsigned long *ru); +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs); +extern int ptrace_cancel_bpt (struct task_struct *); +extern int ptrace_set_bpt (struct task_struct *); + +/* + * atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs) +{ + + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + regs->ARM_r0 = -EINTR; + + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return regs->ARM_r0; + } +} + +asmlinkage int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sigmask_lock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + regs->ARM_r0 = -EINTR; + + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return regs->ARM_r0; + } +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +/* + * Do a signal return; undo the signal stack. + */ +struct sigframe +{ + struct sigcontext sc; + unsigned long extramask[_NSIG_WORDS-1]; + unsigned long retcode; +}; + +struct rt_sigframe +{ + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + unsigned long retcode; +}; + +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +{ + __get_user(regs->ARM_r0, &sc->arm_r0); + __get_user(regs->ARM_r1, &sc->arm_r1); + __get_user(regs->ARM_r2, &sc->arm_r2); + __get_user(regs->ARM_r3, &sc->arm_r3); + __get_user(regs->ARM_r4, &sc->arm_r4); + __get_user(regs->ARM_r5, &sc->arm_r5); + __get_user(regs->ARM_r6, &sc->arm_r6); + __get_user(regs->ARM_r7, &sc->arm_r7); + __get_user(regs->ARM_r8, &sc->arm_r8); + __get_user(regs->ARM_r9, &sc->arm_r9); + __get_user(regs->ARM_r10, &sc->arm_r10); + __get_user(regs->ARM_fp, &sc->arm_fp); + __get_user(regs->ARM_ip, &sc->arm_ip); + __get_user(regs->ARM_sp, &sc->arm_sp); + __get_user(regs->ARM_lr, &sc->arm_lr); + __get_user(regs->ARM_pc, &sc->arm_pc); /* security! */ +#if defined(CONFIG_CPU_ARM6) || defined(CONFIG_CPU_SA110) + __get_user(regs->ARM_cpsr, &sc->arm_cpsr); /* security! */ +#endif + + /* send SIGTRAP if we're single-stepping */ + if (ptrace_cancel_bpt (current)) + send_sig (SIGTRAP, current, 1); + + return regs->ARM_r0; +} + +asmlinkage int sys_sigreturn(struct pt_regs *regs) +{ + struct sigframe *frame; + sigset_t set; + + frame = (struct sigframe *)regs->ARM_sp; + + if (verify_area(VERIFY_READ, frame, sizeof (*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + return restore_sigcontext(regs, &frame->sc); + +badframe: + lock_kernel(); + do_exit(SIGSEGV); +} + +asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_sigframe *frame; + sigset_t set; + + frame = (struct rt_sigframe *)regs->ARM_sp; + + if (verify_area(VERIFY_READ, frame, sizeof (*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + return restore_sigcontext(regs, &frame->uc.uc_mcontext); + +badframe: + lock_kernel(); + do_exit(SIGSEGV); +} + +static void +setup_sigcontext(struct sigcontext *sc, /*struct _fpstate *fpstate,*/ + struct pt_regs *regs, unsigned long mask) +{ + __put_user (regs->ARM_r0, &sc->arm_r0); + __put_user (regs->ARM_r1, &sc->arm_r1); + __put_user (regs->ARM_r2, &sc->arm_r2); + __put_user (regs->ARM_r3, &sc->arm_r3); + __put_user (regs->ARM_r4, &sc->arm_r4); + __put_user (regs->ARM_r5, &sc->arm_r5); + __put_user (regs->ARM_r6, &sc->arm_r6); + __put_user (regs->ARM_r7, &sc->arm_r7); + __put_user (regs->ARM_r8, &sc->arm_r8); + __put_user (regs->ARM_r9, &sc->arm_r9); + __put_user (regs->ARM_r10, &sc->arm_r10); + __put_user (regs->ARM_fp, &sc->arm_fp); + __put_user (regs->ARM_ip, &sc->arm_ip); + __put_user (regs->ARM_sp, &sc->arm_sp); + __put_user (regs->ARM_lr, &sc->arm_lr); + __put_user (regs->ARM_pc, &sc->arm_pc); /* security! */ +#if defined(CONFIG_CPU_ARM6) || defined(CONFIG_CPU_SA110) + __put_user (regs->ARM_cpsr, &sc->arm_cpsr); /* security! */ +#endif + + __put_user (current->tss.trap_no, &sc->trap_no); + __put_user (current->tss.error_code, &sc->error_code); + __put_user (mask, &sc->oldmask); +} + +static void setup_frame(int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe *frame; + unsigned long retcode; + + frame = (struct sigframe *)regs->ARM_sp - 1; + + if (!access_ok(VERIFT_WRITE, frame, sizeof (*frame))) + goto segv_and_exit; + + setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); + + if (_NSIG_WORDS > 1) { + __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + retcode = (unsigned long)ka->sa.sa_restorer; /* security! */ + } else { + retcode = (unsigned long)&frame->retcode; + __put_user(SWI_SYS_SIGRETURN, &frame->retcode); + __flush_entry_to_ram (&frame->retcode); + } + + if (current->exec_domain && current->exec_domain->signal_invmap && sig < 32) + regs->ARM_r0 = current->exec_domain->signal_invmap[sig]; + else + regs->ARM_r0 = sig; + regs->ARM_sp = (unsigned long)frame; + regs->ARM_lr = retcode; + regs->ARM_pc = (unsigned long)ka->sa.sa_handler; /* security! */ + return; + +segv_and_exit: + lock_kernel(); + do_exit (SIGSEGV); +} + +static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + unsigned long retcode; + + frame = (struct rt_sigframe *)regs->ARM_sp - 1; + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + goto segv_and_exit; + + __put_user(&frame->info, &frame->pinfo); + __put_user(&frame->uc, &frame->puc); + __copy_to_user(&frame->info, info, sizeof(*info)); + + /* Clear all the bits of the ucontext we don't use. */ + __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + + setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ + regs, set->sig[0]); + __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + if (ka->sa.sa_flags & SA_RESTORER) { + retcode = (unsigned long)ka->sa.sa_restorer; /* security! */ + } else { + retcode = (unsigned long)&frame->retcode; + __put_user(SWI_SYS_RT_SIGRETURN, &frame->retcode); + __flush_entry_to_ram (&frame->retcode); + } + + if (current->exec_domain && current->exec_domain->signal_invmap && sig < 32) + regs->ARM_r0 = current->exec_domain->signal_invmap[sig]; + else + regs->ARM_r0 = sig; + regs->ARM_sp = (unsigned long)frame; + regs->ARM_lr = retcode; + regs->ARM_pc = (unsigned long)ka->sa.sa_handler; /* security! */ + return; + +segv_and_exit: + lock_kernel(); + do_exit (SIGSEGV); +} + +/* + * OK, we're invoking a handler + */ +static void +handle_signal(unsigned long sig, struct k_sigaction *ka, + siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) +{ + /* Set up the stack frame */ + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); + + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(¤t->sigmask_lock); + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + } +} + +/* + * 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. + * + * Note that we go through the signals twice: once to check the signals that + * the kernel can handle, and then we build all the user-level signal handling + * stack-frames in one go after that. + */ +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) +{ + unsigned long instr, *pc = (unsigned long *)(instruction_pointer(regs)-4); + struct k_sigaction *ka; + siginfo_t info; + int single_stepping, swi_instr; + + if (!oldset) + oldset = ¤t->blocked; + + single_stepping = ptrace_cancel_bpt (current); + swi_instr = (!get_user (instr, pc) && (instr & 0x0f000000) == 0x0f000000); + + for (;;) { + unsigned long signr; + + spin_lock_irq (¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq (¤t->sigmask_lock); + + if (!signr) + break; + + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + /* Let the debugger run. */ + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + single_stepping |= ptrace_cancel_bpt (current); + + /* We're back. Did the debugger cancel the sig? */ + if (!(signr = current->exit_code)) + continue; + current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ + if (signr == SIGSTOP) + continue; + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); + continue; + } + } + + ka = ¤t->sig->action[signr-1]; + if (ka->sa.sa_handler == SIG_IGN) { + if (signr != SIGCHLD) + continue; + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + /* nothing */; + continue; + } + + if (ka->sa.sa_handler == SIG_DFL) { + int exit_code = signr; + + /* Init gets no signals it doesn't want. */ + if (current->pid == 1) + continue; + + switch (signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + /* FALLTHRU */ + + case SIGSTOP: + current->state = TASK_STOPPED; + current->exit_code = signr; + if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) + notify_parent(current, SIGCHLD); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGABRT: case SIGFPE: case SIGSEGV: + lock_kernel(); + if (current->binfmt + && current->binfmt->core_dump + && current->binfmt->core_dump(signr, regs)) + exit_code |= 0x80; + unlock_kernel(); + /* FALLTHRU */ + + default: + lock_kernel(); + sigaddset(¤t->signal, signr); + current->flags |= PF_SIGNALED; + do_exit(exit_code); + /* NOTREACHED */ + } + } + + /* Are we from a system call? */ + if (swi_instr) { + switch (regs->ARM_r0) { + case -ERESTARTNOHAND: + regs->ARM_r0 = -EINTR; + break; + + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->ARM_r0 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + regs->ARM_r0 = regs->ARM_ORIG_r0; + regs->ARM_pc -= 4; + } + } + /* Whee! Actually deliver the signal. */ + handle_signal(signr, ka, &info, oldset, regs); + if (single_stepping) + ptrace_set_bpt (current); + return 1; + } + + if (swi_instr && + (regs->ARM_r0 == -ERESTARTNOHAND || + regs->ARM_r0 == -ERESTARTSYS || + regs->ARM_r0 == -ERESTARTNOINTR)) { + regs->ARM_r0 = regs->ARM_ORIG_r0; + regs->ARM_pc -= 4; + } + if (single_stepping) + ptrace_set_bpt (current); + return 0; +} 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 Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/sys_arm.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,372 @@ +/* + * linux/arch/arm/kernel/sys_arm.c + * + * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c + * Copyright (C) 1995, 1996 Russell King. + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/arm + * platform. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Constant strings used in inlined functions in header files + */ +/* proc/system.h */ +const char xchg_str[] = "xchg"; +/* arch/dma.h */ +const char dma_str[] = "%s: dma %d not supported\n"; + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +asmlinkage int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + lock_kernel(); + error = do_pipe(fd); + unlock_kernel(); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. ARM Linux didn't use to be able to handle more than + * 4 system call parameters, so these system calls used a memory + * block for parameter passing.. + */ + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +asmlinkage int old_mmap(struct mmap_arg_struct *arg) +{ + int error = -EFAULT; + struct file * file = NULL; + struct mmap_arg_struct a; + + lock_kernel(); + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + if (!(a.flags & MAP_ANONYMOUS)) { + error = -EBADF; + if (a.fd >= NR_OPEN || !(file = current->files->fd[a.fd])) + goto out; + } + a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset); +out: + unlock_kernel(); + return error; +} + + +extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); + +struct sel_arg_struct { + unsigned long n; + fd_set *inp, *outp, *exp; + struct timeval *tvp; +}; + +asmlinkage int old_select(struct sel_arg_struct *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + /* sys_select() does the appropriate kernel locking */ + return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +{ + int version, ret; + + lock_kernel(); + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + ret = sys_semop (first, (struct sembuf *)ptr, second); + goto out; + case SEMGET: + ret = sys_semget (first, second, third); + goto out; + case SEMCTL: { + union semun fourth; + ret = -EINVAL; + if (!ptr) + goto out; + ret = -EFAULT; + if (get_user(fourth.__pad, (void **) ptr)) + goto out; + ret = sys_semctl (first, second, third, fourth); + goto out; + } + default: + ret = -EINVAL; + goto out; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + ret = sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + goto out; + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + ret = -EINVAL; + if (!ptr) + goto out; + ret = -EFAULT; + if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, + sizeof (tmp))) + goto out; + ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); + goto out; + } + case 1: default: + ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third); + goto out; + } + case MSGGET: + ret = sys_msgget ((key_t) first, second); + goto out; + case MSGCTL: + ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + goto out; + default: + ret = -EINVAL; + goto out; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: + switch (version) { + case 0: default: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + goto out; + ret = put_user (raddr, (ulong *) third); + goto out; + } + case 1: /* iBCS2 emulator entry point */ + ret = -EINVAL; + if (!segment_eq(get_fs(), get_ds())) + goto out; + ret = sys_shmat (first, (char *) ptr, second, (ulong *) third); + goto out; + } + case SHMDT: + ret = sys_shmdt ((char *)ptr); + goto out; + case SHMGET: + ret = sys_shmget (first, second, third); + goto out; + case SHMCTL: + ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + goto out; + default: + ret = -EINVAL; + goto out; + } + else + ret = -EINVAL; +out: + unlock_kernel(); + return ret; +} + +/* Fork a new task - this creates a new program thread. + * This is called indirectly via a small wrapper + */ +asmlinkage int sys_fork(struct pt_regs *regs) +{ + int ret; + + lock_kernel(); + ret = do_fork(SIGCHLD, regs->ARM_sp, regs); + unlock_kernel(); + + return ret; +} + +/* Clone a task - this clones the calling program thread. + * This is called indirectly via a small wrapper + */ +asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs) +{ + int ret; + + lock_kernel(); + if (!newsp) + newsp = regs->ARM_sp; + + ret = do_fork(clone_flags, newsp, regs); + unlock_kernel(); + return ret; +} + +/* sys_execve() executes a new program. + * This is called indirectly via a small wrapper + */ +asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, struct pt_regs *regs) +{ + int error; + char * filename; + + lock_kernel(); + filename = getname(filenamei); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); +out: + unlock_kernel(); + return error; +} + +/* + * Detect the old function calling standard + */ +static inline unsigned long old_calling_standard (struct pt_regs *regs) +{ + unsigned long instr, *pcv = (unsigned long *)(instruction_pointer(regs) - 8); + return (!get_user (instr, pcv) && instr == 0xe1a0300d); +} + +/* Compatability functions - we used to pass 5 parameters as r0, r1, r2, *r3, *(r3+4) + * We now use r0 - r4, and return an error if the old style calling standard is used. + * Eventually these functions will disappear. + */ +asmlinkage int +sys_compat_llseek (unsigned int fd, unsigned long offset_high, unsigned long offset_low, + loff_t *result, unsigned int origin, struct pt_regs *regs) +{ + extern int sys_llseek (unsigned int, unsigned long, unsigned long, loff_t *, unsigned int); + + if (old_calling_standard (regs)) { + printk (KERN_NOTICE "%s (%d): unsupported llseek call standard\n", + current->comm, current->pid); + return -EINVAL; + } + return sys_llseek (fd, offset_high, offset_low, result, origin); +} + +asmlinkage int +sys_compat_mount (char *devname, char *dirname, char *type, unsigned long flags, void *data, + struct pt_regs *regs) +{ + extern int sys_mount (char *, char *, char *, unsigned long, void *); + + if (old_calling_standard (regs)) { + printk (KERN_NOTICE "%s (%d): unsupported mount call standard\n", + current->comm, current->pid); + return -EINVAL; + } + return sys_mount (devname, dirname, type, flags, data); +} + +asmlinkage int sys_uname (struct old_utsname * name) +{ + static int warned = 0; + + if (warned == 0) { + warned ++; + printk (KERN_NOTICE "%s (%d): obsolete uname call\n", + current->comm, current->pid); + } + + if (name && !copy_to_user (name, &system_utsname, sizeof (*name))) + return 0; + return -EFAULT; +} + +asmlinkage int sys_olduname(struct oldold_utsname * name) +{ + int error; + static int warned = 0; + + if (warned == 0) { + warned ++; + printk (KERN_NOTICE "%s (%d): obsolete olduname call\n", + current->comm, current->pid); + } + + if (!name) + return -EFAULT; + + if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) + return -EFAULT; + + error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + error -= __put_user(0,name->sysname+__OLD_UTS_LEN); + error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error -= __put_user(0,name->nodename+__OLD_UTS_LEN); + error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error -= __put_user(0,name->release+__OLD_UTS_LEN); + error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error -= __put_user(0,name->version+__OLD_UTS_LEN); + error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error -= __put_user(0,name->machine+__OLD_UTS_LEN); + error = error ? -EFAULT : 0; + + return error; +} + +asmlinkage int sys_pause(void) +{ + static int warned = 0; + + if (warned == 0) { + warned ++; + printk (KERN_NOTICE "%s (%d): obsolete pause call\n", + current->comm, current->pid); + } + + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + 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 Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/time.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,154 @@ +/* + * linux/arch/arm/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King + * + * This file contains the ARM-specific time handling details: + * reading the RTC at bootup, etc... + * + * 1994-07-02 Alan Modra + * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +extern int setup_arm_irq(int, struct irqaction *); +extern volatile unsigned long lost_ticks; + +/* change this if you have some constant time drift */ +#define USECS_PER_JIFFY (1000000/HZ) + +#ifndef BCD_TO_BIN +#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) +#endif + +#ifndef BIN_TO_BCD +#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) +#endif + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long mktime(unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + return ((( + (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + +#include + +static unsigned long do_gettimeoffset(void) +{ + return gettimeoffset (); +} + +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + + save_flags_cli (flags); + *tv = xtime; + tv->tv_usec += do_gettimeoffset(); + + /* + * xtime is atomically updated in timer_bh. lost_ticks is + * nonzero if the tiemr bottom half hasnt executed yet. + */ + if (lost_ticks) + tv->tv_usec += USECS_PER_JIFFY; + + restore_flags(flags); + + if (tv->tv_usec >= 1000000) { + tv->tv_usec -= 1000000; + tv->tv_sec++; + } +} + +void do_settimeofday(struct timeval *tv) +{ + cli (); + /* This is revolting. We need to set the xtime.tv_usec + * correctly. However, the value in this location is + * is value at the last tick. + * Discover what correction gettimeofday + * would have done, and then undo it! + */ + tv->tv_usec -= do_gettimeoffset(); + + if (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime = *tv; + time_state = TIME_BAD; + time_maxerror = MAXPHASE; + time_esterror = MAXPHASE; + sti (); +} + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick. + */ +static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (reset_timer ()) + do_timer(regs); + + update_rtc (); +} + +static struct irqaction irqtimer0 = { timer_interrupt, 0, 0, "timer", NULL, NULL}; + +void time_init(void) +{ + xtime.tv_sec = setup_timer(); + xtime.tv_usec = 0; + + setup_arm_irq(IRQ_TIMER0, &irqtimer0); +} diff -ur --new-file old/linux/arch/arm/kernel/traps.c new/linux/arch/arm/kernel/traps.c --- old/linux/arch/arm/kernel/traps.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/kernel/traps.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,306 @@ +/* + * linux/arch/arm/kernel/traps.c + * + * Copyright (C) 1995, 1996 Russell King + * Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds + */ + +/* + * 'traps.c' handles hardware exceptions after we have saved some state in + * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably + * kill the offending process. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern void fpe_save(struct fp_soft_struct *); +extern void fpe_restore(struct fp_soft_struct *); +extern void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret); +extern void c_backtrace (unsigned long fp, int pmode); +extern int ptrace_cancel_bpt (struct task_struct *); + +char *processor_modes[]= +{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , + "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", + "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , + "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32" +}; + +static char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; + +static inline void console_verbose(void) +{ + extern int console_loglevel; + console_loglevel = 15; +} + +int kstack_depth_to_print = 200; + +static int verify_stack_pointer (unsigned long stackptr, int size) +{ +#if defined(CONFIG_CPU_ARM2) || defined(CONFIG_CPU_ARM3) + if (stackptr < 0x02048000 || stackptr + size > 0x03000000) + return -EFAULT; +#else + if (stackptr < 0xc0000000 || stackptr + size > (unsigned long)high_memory) + return -EFAULT; +#endif + return 0; +} + +static void dump_stack (unsigned long *start, unsigned long *end, int offset, int max) +{ + unsigned long *p; + int i; + + for (p = start + offset, i = 0; i < max && p < end; i++, p++) { + if (i && (i & 7) == 0) + printk ("\n "); + printk ("%08lx ", *p); + } + printk ("\n"); +} + +/* + * These constants are for searching for possible module text + * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is + * a guess of how much space is likely to be vmalloced. + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define MODULE_RANGE (8*1024*1024) + +static void dump_instr (unsigned long pc) +{ + unsigned long module_start, module_end; + int pmin = -2, pmax = 3, ok = 0; + extern char start_kernel, _etext; + + module_start = VMALLOC_START; + module_end = module_start + MODULE_RANGE; + + if ((pc >= (unsigned long) &start_kernel) && + (pc <= (unsigned long) &_etext)) { + if (pc + pmin < (unsigned long) &start_kernel) + pmin = ((unsigned long) &start_kernel) - pc; + if (pc + pmax > (unsigned long) &_etext) + pmax = ((unsigned long) &_etext) - pc; + ok = 1; + } else if (pc >= module_start && pc <= module_end) { + if (pc + pmin < module_start) + pmin = module_start - pc; + if (pc + pmax > module_end) + pmax = module_end - pc; + ok = 1; + } + printk ("Code: "); + if (ok) { + int i; + for (i = pmin; i < pmax; i++) + printk("%08lx ", ((unsigned long *)pc)[i]); + printk ("\n"); + } else + printk ("pc not in code space\n"); +} + +/* + * This function is protected against kernel-mode re-entrancy. If it + * is re-entered it will hang the system since we can't guarantee in + * this case that any of the functions that it calls are safe any more. + * Even the panic function could be a problem, but we'll give it a go. + */ +void die_if_kernel(char *str, struct pt_regs *regs, int err, int ret) +{ + static int died = 0; + unsigned long cstack, sstack, frameptr; + + if (user_mode(regs)) + return; + + switch (died) { + case 2: + while (1); + case 1: + died ++; + panic ("die_if_kernel re-entered. Major kernel corruption. Please reboot me!"); + break; + case 0: + died ++; + break; + } + + console_verbose (); + printk ("Internal error: %s: %x\n", str, err); + printk ("CPU: %d", smp_processor_id()); + show_regs (regs); + printk ("Process %s (pid: %d, stackpage=%08lx)\nStack: ", + current->comm, current->pid, 4096+(unsigned long)current); + + cstack = (unsigned long)(regs + 1); + sstack = 4096+(unsigned long)current; + + if (*(unsigned long *)sstack != STACK_MAGIC) + printk ("*** corrupted stack page\n "); + + if (verify_stack_pointer (cstack, 4)) + printk ("%08lx invalid kernel stack pointer\n", cstack); + else if(cstack > sstack + 4096) + printk("(sp overflow)\n"); + else if(cstack < sstack) + printk("(sp underflow)\n"); + else + dump_stack ((unsigned long *)sstack, (unsigned long *)sstack + 1024, + cstack - sstack, kstack_depth_to_print); + + frameptr = regs->ARM_fp; + if (frameptr) { + if (verify_stack_pointer (frameptr, 4)) + printk ("Backtrace: invalid frame pointer\n"); + else { + printk("Backtrace: \n"); + c_backtrace (frameptr, processor_mode(regs)); + } + } + + dump_instr (instruction_pointer(regs)); + died = 0; + if (ret != -1) + do_exit (ret); + else { + cli (); + while (1); + } +} + +void bad_user_access_alignment (const void *ptr) +{ + void *pc; + __asm__("mov %0, lr\n": "=r" (pc)); + printk (KERN_ERR "bad_user_access_alignment called: ptr = %p, pc = %p\n", ptr, pc); + current->tss.error_code = 0; + current->tss.trap_no = 11; + force_sig (SIGBUS, current); +/* die_if_kernel("Oops - bad user access alignment", regs, mode, SIGBUS);*/ +} + +asmlinkage void do_undefinstr (int address, struct pt_regs *regs, int mode) +{ + current->tss.error_code = 0; + current->tss.trap_no = 6; + force_sig (SIGILL, current); + die_if_kernel("Oops - undefined instruction", regs, mode, SIGILL); +} + +asmlinkage void do_excpt (int address, struct pt_regs *regs, int mode) +{ + current->tss.error_code = 0; + current->tss.trap_no = 11; + force_sig (SIGBUS, current); + die_if_kernel("Oops - address exception", regs, mode, SIGBUS); +} + +asmlinkage void do_unexp_fiq (struct pt_regs *regs) +{ +#ifndef CONFIG_IGNORE_FIQ + printk ("Hmm. Unexpected FIQ received, but trying to continue\n"); + printk ("You may have a hardware problem...\n"); +#endif +} + +asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode) +{ + printk (KERN_CRIT "Bad mode in %s handler detected: mode %s\n", + handler[reason], + processor_modes[proc_mode]); + die_if_kernel ("Oops", regs, 0, -1); +} + +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task. + * + * We no longer save/restore the math state on every context switch + * any more. We only do this now if it actually gets used. + */ +asmlinkage void math_state_restore (void) +{ + if (last_task_used_math == current) + return; + if (last_task_used_math) + /* + * Save current fp state into last_task_used_math->tss.fpe_save + */ + fpe_save (&last_task_used_math->tss.fpstate.soft); + last_task_used_math = current; + if (current->used_math) { + /* + * Restore current fp state from current->tss.fpe_save + */ + fpe_restore (¤t->tss.fpstate.soft); + } else { + /* + * initialise fp state + */ + fpe_restore (&init_task.tss.fpstate.soft); + current->used_math = 1; + } +} + +asmlinkage void arm_syscall (int no, struct pt_regs *regs) +{ + switch (no) { + case 0: /* branch through 0 */ + printk ("[%d] %s: branch through zero\n", current->pid, current->comm); + force_sig (SIGILL, current); + if (user_mode(regs)) { + show_regs (regs); + c_backtrace (regs->ARM_fp, processor_mode(regs)); + } + die_if_kernel ("Oops", regs, 0, SIGILL); + break; + + case 1: /* SWI_BREAK_POINT */ + regs->ARM_pc -= 4; /* Decrement PC by one instruction */ + ptrace_cancel_bpt (current); + force_sig (SIGTRAP, current); + break; + + default: + printk ("[%d] %s: arm syscall %d\n", current->pid, current->comm, no); + force_sig (SIGILL, current); + if (user_mode(regs)) { + show_regs (regs); + c_backtrace (regs->ARM_fp, processor_mode(regs)); + } + die_if_kernel ("Oops", regs, no, SIGILL); + break; + } +} + +asmlinkage void deferred(int n, struct pt_regs *regs) +{ + printk ("[%d] %s: old system call %X\n", current->pid, current->comm, n); + show_regs (regs); + force_sig (SIGILL, current); +} + +asmlinkage void arm_malalignedptr(const char *str, void *pc, volatile void *ptr) +{ + printk ("Mal-aligned pointer in %s: %p (PC=%p)\n", str, ptr, pc); +} + +asmlinkage void arm_invalidptr (const char *function, int size) +{ + printk ("Invalid pointer size in %s (PC=%p) size %d\n", + function, __builtin_return_address(0), size); +} diff -ur --new-file old/linux/arch/arm/lib/Makefile new/linux/arch/arm/lib/Makefile --- old/linux/arch/arm/lib/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/Makefile Wed Jan 21 01:39:41 1998 @@ -0,0 +1,55 @@ +# +# linux/arch/arm/lib/Makefile +# +# Copyright (C) 1995-1998 Russell King +# + +L_TARGET := lib.a +L_OBJS := backtrace.o bitops.o delay.o fp_support.o \ + loaders.o memcpy.o memfastset.o system.o string.o uaccess.o + +ifeq ($(PROCESSOR),armo) + L_OBJS += uaccess-armo.o +endif + +ifdef CONFIG_INET + L_OBJS += checksum.o +endif + +ifdef CONFIG_ARCH_ACORN + L_OBJS += ll_char_wr.o io-acorn.o + ifdef CONFIG_ARCH_A5K + L_OBJS += floppydma.o + endif + ifdef CONFIG_ARCH_RPC + L_OBJS += floppydma.o + endif +endif + +ifdef CONFIG_ARCH_EBSA110 + L_OBJS += io-ebsa110.o +endif + +include $(TOPDIR)/Rules.make + +constants.h: getconstants + ./getconstants > constants.h + +getconstants: getconstants.c getconstants.h + $(HOSTCC) -D__KERNEL__ -o getconstants getconstants.c + +getconstants.h: getconsdata.c + $(CC) $(CFLAGS) -c getconsdata.c + $(PERL) extractinfo.perl $(OBJDUMP) > $@ + +%.o: %.S +ifndef $(CONFIG_BINUTILS_NEW) + $(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 + +clean: + $(RM) getconstants constants.h getconstants.h diff -ur --new-file old/linux/arch/arm/lib/backtrace.S new/linux/arch/arm/lib/backtrace.S --- old/linux/arch/arm/lib/backtrace.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/backtrace.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,100 @@ +/* + * linux/arch/arm/lib/backtrace.S + * + * Copyright (C) 1995, 1996 Russell King + */ +#include +#include + .text + +@ fp is 0 or stack frame + +#define frame r4 +#define next r5 +#define save r6 +#define mask r7 +#define offset r8 + +ENTRY(__backtrace) + mov r1, #0x10 + mov r0, fp + +ENTRY(c_backtrace) + stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... + tst r1, #0x10 @ 26 or 32-bit? + moveq mask, #0xfc000003 + movne mask, #0 + tst mask, r0 + movne r0, #0 + movs frame, r0 +1: moveq r0, #-2 + LOADREGS(eqfd, sp!, {r4 - r8, pc}) + +2: stmfd sp!, {pc} @ calculate offset of PC in STMIA instruction + ldr r0, [sp], #4 + adr r1, 2b - 4 + sub offset, r0, r1 + +3: tst frame, mask @ Check for address exceptions... + bne 1b + + ldmda frame, {r0, r1, r2, r3} @ fp, sp, lr, pc + mov next, r0 + + sub save, r3, offset @ Correct PC for prefetching + bic save, save, mask + adr r0, .Lfe + mov r1, save + bic r2, r2, mask + bl SYMBOL_NAME(printk) + + sub r0, frame, #16 + ldr r1, [save, #4] + mov r3, r1, lsr #10 + ldr r2, .Ldsi+4 + teq r3, r2 @ Check for stmia sp!, {args} + addeq save, save, #4 @ next instruction + bleq .Ldumpstm + + ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction + mov r3, r1, lsr #10 + ldr r2, .Ldsi + teq r3, r2 + bleq .Ldumpstm + + teq frame, next + movne frame, next + teqne frame, #0 + bne 3b + LOADREGS(fd, sp!, {r4 - r8, pc}) + + +#define instr r4 +#define reg r5 +#define stack r6 + +.Ldumpstm: stmfd sp!, {instr, reg, stack, lr} + mov stack, r0 + mov instr, r1 + mov reg, #9 + +1: mov r3, #1 + tst instr, r3, lsl reg + beq 2f + ldr r2, [stack], #-4 + mov r1, reg + adr r0, .Lfp + bl SYMBOL_NAME(printk) +2: subs reg, reg, #1 + bpl 1b + + mov r0, stack + LOADREGS(fd, sp!, {instr, reg, stack, pc}) + +.Lfe: .ascii "Function entered at [<%p>] from [<%p>]\n" + .byte 0 +.Lfp: .ascii " r%d = %p\n" + .byte 0 + .align +.Ldsi: .word 0x00e92dd8 >> 2 + .word 0x00e92d00 >> 2 diff -ur --new-file old/linux/arch/arm/lib/bitops.S new/linux/arch/arm/lib/bitops.S --- old/linux/arch/arm/lib/bitops.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/bitops.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,152 @@ +/* + * linux/arch/arm/lib/bitops.S + * + * Copyright (C) 1995, 1996 Russell King + */ + +#include +#include + .text + +@ Purpose : Function to set a bit +@ Prototype: int set_bit(int bit,int *addr) + +ENTRY(set_bit) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1, r0, lsr #3] + orr r2, r2, r3 + strb r2, [r1, r0, lsr #3] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + +ENTRY(test_and_set_bit) + add r1, r1, r0, lsr #3 @ Get byte offset + and r3, r0, #7 @ Get bit offset + mov r0, #1 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1] + tst r2, r0, lsl r3 + orr r2, r2, r0, lsl r3 + moveq r0, #0 + strb r2, [r1] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + +@ Purpose : Function to clear a bit +@ Prototype: int clear_bit(int bit,int *addr) + +ENTRY(clear_bit) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1, r0, lsr #3] + bic r2, r2, r3 + strb r2, [r1, r0, lsr #3] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + +ENTRY(test_and_clear_bit) + add r1, r1, r0, lsr #3 @ Get byte offset + and r3, r0, #7 @ Get bit offset + mov r0, #1 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1] + tst r2, r0, lsl r3 + bic r2, r2, r0, lsl r3 + moveq r0, #0 + strb r2, [r1] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + +/* Purpose : Function to change a bit + * Prototype: int change_bit(int bit,int *addr) + */ +ENTRY(change_bit) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1, r0, lsr #3] + eor r2, r2, r3 + strb r2, [r1, r0, lsr #3] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + +ENTRY(test_and_change_bit) + add r1, r1, r0, lsr #3 + and r3, r0, #7 + mov r0, #1 + SAVEIRQS(ip) + DISABLEIRQS(ip) + ldrb r2, [r1] + tst r2, r0, lsl r3 + eor r2, r2, r0, lsl r3 + moveq r0, #0 + strb r2, [r1] + RESTOREIRQS(ip) + RETINSTR(mov,pc,lr) + +@ Purpose : Find a 'zero' bit +@ Prototype: int find_first_zero_bit(char *addr,int maxbit); + +ENTRY(find_first_zero_bit) + mov r2, #0 @ Initialise bit position +Lfindzbit1lp: ldrb r3, [r0, r2, lsr #3] @ Check byte, if 0xFF, then all bits set + teq r3, #0xFF + bne Lfoundzbit + add r2, r2, #8 + cmp r2, r1 @ Check to see if we have come to the end + bcc Lfindzbit1lp + add r0, r1, #1 @ Make sure that we flag an error + RETINSTR(mov,pc,lr) +Lfoundzbit: tst r3, #1 @ Check individual bits + moveq r0, r2 + RETINSTR(moveq,pc,lr) + tst r3, #2 + addeq r0, r2, #1 + RETINSTR(moveq,pc,lr) + tst r3, #4 + addeq r0, r2, #2 + RETINSTR(moveq,pc,lr) + tst r3, #8 + addeq r0, r2, #3 + RETINSTR(moveq,pc,lr) + tst r3, #16 + addeq r0, r2, #4 + RETINSTR(moveq,pc,lr) + tst r3, #32 + addeq r0, r2, #5 + RETINSTR(moveq,pc,lr) + tst r3, #64 + addeq r0, r2, #6 + RETINSTR(moveq,pc,lr) + add r0, r2, #7 + RETINSTR(mov,pc,lr) + +@ Purpose : Find next 'zero' bit +@ Prototype: int find_next_zero_bit(char *addr,int maxbit,int offset) + +ENTRY(find_next_zero_bit) + tst r2, #7 + beq Lfindzbit1lp @ If new byte, goto old routine + ldrb r3, [r0, r2, lsr#3] + orr r3, r3, #0xFF00 @ Set top bits so we wont get confused + stmfd sp!, {r4} + and r4, r2, #7 + mov r3, r3, lsr r4 @ Shift right by no. of bits + ldmfd sp!, {r4} + and r3, r3, #0xFF + teq r3, #0xFF + orreq r2, r2, #7 + addeq r2, r2, #1 + beq Lfindzbit1lp @ If all bits are set, goto old routine + b Lfoundzbit diff -ur --new-file old/linux/arch/arm/lib/checksum.S new/linux/arch/arm/lib/checksum.S --- old/linux/arch/arm/lib/checksum.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/checksum.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,600 @@ +/* + * linux/arch/arm/lib/iputils.S + * + * Copyright (C) 1995, 1996, 1997, 1998 Russell King + */ +#include +#include +#include + + .text + +/* Function: __u32 csum_partial(const char *src, int len, __u32) + * Params : r0 = buffer, r1 = len, r2 = checksum + * Returns : r0 = new checksum + */ + +ENTRY(csum_partial) + tst r0, #2 + beq 1f + subs r1, r1, #2 + addmi r1, r1, #2 + bmi 3f + bic r0, r0, #3 + ldr r3, [r0], #4 + adds r2, r2, r3, lsr #16 + adcs r2, r2, #0 +1: adds r2, r2, #0 + bics ip, r1, #31 + beq 3f + stmfd sp!, {r4 - r6} +2: ldmia r0!, {r3 - r6} + adcs r2, r2, r3 + adcs r2, r2, r4 + adcs r2, r2, r5 + adcs r2, r2, r6 + ldmia r0!, {r3 - r6} + adcs r2, r2, r3 + adcs r2, r2, r4 + adcs r2, r2, r5 + adcs r2, r2, r6 + sub ip, ip, #32 + teq ip, #0 + bne 2b + adcs r2, r2, #0 + ldmfd sp!, {r4 - r6} +3: ands ip, r1, #0x1c + beq 5f +4: ldr r3, [r0], #4 + adcs r2, r2, r3 + sub ip, ip, #4 + teq ip, #0 + bne 4b + adcs r2, r2, #0 +5: ands ip, r1, #3 + moveq r0, r2 + RETINSTR(moveq,pc,lr) + mov ip, ip, lsl #3 + rsb ip, ip, #32 + ldr r3, [r0] + mov r3, r3, lsl ip + adds r2, r2, r3, lsr ip + adc r0, r2, #0 + RETINSTR(mov,pc,lr) + +/* Function: __u32 csum_partial_copy_from_user (const char *src, char *dst, int len, __u32 sum, int *err_ptr) + * Params : r0 = src, r1 = dst, r2 = len, r3 = sum, [sp, #0] = &err + * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT + */ + +#define USER_LDR(instr...) \ +9999: instr; \ + .section __ex_table, "a"; \ + .align 3; \ + .long 9999b, 6001f; \ + .previous; + +ENTRY(csum_partial_copy_from_user) + mov ip, sp + stmfd sp!, {r4 - r8, fp, ip, lr, pc} + sub fp, ip, #4 + cmp r2, #4 + blt .too_small_user + tst r1, #2 @ Test destination alignment + beq .dst_aligned_user + subs r2, r2, #2 @ We dont know if SRC is aligned... +USER_LDR( ldrbt ip, [r0], #1) +USER_LDR( ldrbt r8, [r0], #1) + orr ip, ip, r8, lsl #8 + adds r3, r3, ip + adcs r3, r3, #0 + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 @ Destination now aligned +.dst_aligned_user: + tst r0, #3 + bne .src_not_aligned_user + adds r3, r3, #0 + bics ip, r2, #15 @ Routine for src & dst aligned + beq 2f +1: +USER_LDR( ldrt r4, [r0], #4) +USER_LDR( ldrt r5, [r0], #4) +USER_LDR( ldrt r6, [r0], #4) +USER_LDR( ldrt r7, [r0], #4) + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f +USER_LDR( ldrt r4, [r0], #4) +USER_LDR( ldrt r5, [r0], #4) + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + tst ip, #4 + beq 4f +3: +USER_LDR( ldrt r4, [r0], #4) + str r4, [r1], #4 + adcs r3, r3, r4 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) +USER_LDR( ldrt r4, [r0], #4) + tst r2, #2 + beq .exit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + mov r4, r4, lsr #8 +.exit: tst r2, #1 + strneb r4, [r1], #1 + andne r4, r4, #255 + adcnes r3, r3, r4 + adcs r0, r3, #0 + LOADREGS(ea,fp,{r4 - r8, fp, sp, pc}) + +.too_small_user: + teq r2, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + cmp r2, #2 + blt .too_small_user1 +USER_LDR( ldrbt ip, [r0], #1) +USER_LDR( ldrbt r8, [r0], #1) + orr ip, ip, r8, lsl #8 + adds r3, r3, ip + strb ip, [r1], #1 + strb r8, [r1], #1 + tst r2, #1 +.too_small_user1: +USER_LDR( ldrnebt ip, [r0], #1) + strneb ip, [r1], #1 + adcnes r3, r3, ip + adcs r0, r3, #0 + LOADREGS(ea,fp,{r4 - r8, fp, sp, pc}) + +.src_not_aligned_user: + cmp r2, #4 + blt .too_small_user + and ip, r0, #3 + bic r0, r0, #3 +USER_LDR( ldrt r4, [r0], #4) + cmp ip, #2 + beq .src2_aligned_user + bhi .src3_aligned_user + mov r4, r4, lsr #8 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: +USER_LDR( ldrt r5, [r0], #4) +USER_LDR( ldrt r6, [r0], #4) +USER_LDR( ldrt r7, [r0], #4) +USER_LDR( ldrt r8, [r0], #4) + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + mov r7, r7, lsr #8 + orr r7, r7, r8, lsl #24 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #8 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f +USER_LDR( ldrt r5, [r0], #4) +USER_LDR( ldrt r6, [r0], #4) + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #8 + tst ip, #4 + beq 4f +3: +USER_LDR( ldrt r5, [r0], #4) + orr r4, r4, r5, lsl #24 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #8 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + tst r2, #2 + beq .exit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + b .exit + +.src2_aligned_user: + mov r4, r4, lsr #16 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: +USER_LDR( ldrt r5, [r0], #4) +USER_LDR( ldrt r6, [r0], #4) +USER_LDR( ldrt r7, [r0], #4) +USER_LDR( ldrt r8, [r0], #4) + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7, lsl #16 + mov r7, r7, lsr #16 + orr r7, r7, r8, lsl #16 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #16 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f +USER_LDR( ldrt r5, [r0], #4) +USER_LDR( ldrt r6, [r0], #4) + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #16 + tst ip, #4 + beq 4f +3: +USER_LDR( ldrt r5, [r0], #4) + orr r4, r4, r5, lsl #16 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #16 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + tst r2, #2 + beq .exit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 +USER_LDR( ldrb r4, [r0], #1) + b .exit + +.src3_aligned_user: + mov r4, r4, lsr #24 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: +USER_LDR( ldrt r5, [r0], #4) +USER_LDR( ldrt r6, [r0], #4) +USER_LDR( ldrt r7, [r0], #4) +USER_LDR( ldrt r8, [r0], #4) + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + mov r7, r7, lsr #24 + orr r7, r7, r8, lsl #8 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #24 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f +USER_LDR( ldrt r5, [r0], #4) +USER_LDR( ldrt r6, [r0], #4) + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #24 + tst ip, #4 + beq 4f +3: +USER_LDR( ldrt r5, [r0], #4) + orr r4, r4, r5, lsl #8 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #24 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + tst r2, #2 + beq .exit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 +USER_LDR( ldrt r4, [r0], #4) + strb r4, [r1], #1 + adcs r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + b .exit + + .section .fixup,"ax" + .align 4 +6001: mov r4, #-EFAULT + ldr r5, [sp, #4*8] + str r4, [r5] + LOADREGS(ea,fp,{r4 - r8, fp, sp, pc}) + +/* Function: __u32 csum_partial_copy (const char *src, char *dst, int len, __u32 sum) + * Params : r0 = src, r1 = dst, r2 = len, r3 = checksum + * Returns : r0 = new checksum + */ +ENTRY(csum_partial_copy) + mov ip, sp + stmfd sp!, {r4 - r8, fp, ip, lr, pc} + sub fp, ip, #4 + cmp r2, #4 + blt Ltoo_small + tst r1, #2 @ Test destination alignment + beq Ldst_aligned + subs r2, r2, #2 @ We dont know if SRC is aligned... + ldrb ip, [r0], #1 + ldrb r8, [r0], #1 + orr ip, ip, r8, lsl #8 + adds r3, r3, ip + adcs r3, r3, #0 + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 @ Destination now aligned +Ldst_aligned: tst r0, #3 + bne Lsrc_not_aligned + adds r3, r3, #0 + bics ip, r2, #15 @ Routine for src & dst aligned + beq 3f +1: ldmia r0!, {r4, r5, r6, r7} + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + sub ip, ip, #16 + teq ip, #0 + bne 1b +3: ands ip, r2, #12 + beq 5f + tst ip, #8 + beq 4f + ldmia r0!, {r4, r5} + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + tst ip, #4 + beq 5f +4: ldr r4, [r0], #4 + str r4, [r1], #4 + adcs r3, r3, r4 +5: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + ldr r4, [r0], #4 + tst r2, #2 + beq Lexit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + b Lexit + +Ltoo_small: teq r2, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + cmp r2, #2 + blt Ltoo_small1 + ldrb ip, [r0], #1 + ldrb r8, [r0], #1 + orr ip, ip, r8, lsl #8 + adds r3, r3, ip + strb ip, [r1], #1 + strb r8, [r1], #1 +Lexit: tst r2, #1 +Ltoo_small1: ldrneb ip, [r0], #1 + strneb ip, [r1], #1 + adcnes r3, r3, ip + adcs r0, r3, #0 + LOADREGS(ea,fp,{r4 - r8, fp, sp, pc}) + +Lsrc_not_aligned: + cmp r2, #4 + blt Ltoo_small + and ip, r0, #3 + bic r0, r0, #3 + ldr r4, [r0], #4 + cmp ip, #2 + beq Lsrc2_aligned + bhi Lsrc3_aligned + mov r4, r4, lsr #8 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: ldmia r0!, {r5, r6, r7, r8} + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + mov r7, r7, lsr #8 + orr r7, r7, r8, lsl #24 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #8 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + ldmia r0!, {r5, r6} + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #8 + tst ip, #4 + beq 4f +3: ldr r5, [r0], #4 + orr r4, r4, r5, lsl #24 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #8 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + tst r2, #2 + beq Lexit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + b Lexit + +Lsrc2_aligned: mov r4, r4, lsr #16 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: ldmia r0!, {r5, r6, r7, r8} + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7, lsl #16 + mov r7, r7, lsr #16 + orr r7, r7, r8, lsl #16 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #16 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + ldmia r0!, {r5, r6} + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #16 + tst ip, #4 + beq 4f +3: ldr r5, [r0], #4 + orr r4, r4, r5, lsl #16 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #16 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + tst r2, #2 + beq Lexit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + mov r4, r4, lsr #8 + strb r4, [r1], #1 + ldrb r4, [r0], #1 + b Lexit + +Lsrc3_aligned: mov r4, r4, lsr #24 + adds r3, r3, #0 + bics ip, r2, #15 + beq 2f +1: ldmia r0!, {r5, r6, r7, r8} + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + mov r7, r7, lsr #24 + orr r7, r7, r8, lsl #8 + stmia r1!, {r4, r5, r6, r7} + adcs r3, r3, r4 + adcs r3, r3, r5 + adcs r3, r3, r6 + adcs r3, r3, r7 + mov r4, r8, lsr #24 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, r2, #12 + beq 4f + tst ip, #8 + beq 3f + ldmia r0!, {r5, r6} + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + stmia r1!, {r4, r5} + adcs r3, r3, r4 + adcs r3, r3, r5 + mov r4, r6, lsr #24 + tst ip, #4 + beq 4f +3: ldr r5, [r0], #4 + orr r4, r4, r5, lsl #8 + str r4, [r1], #4 + adcs r3, r3, r4 + mov r4, r5, lsr #24 +4: ands r2, r2, #3 + adceq r0, r3, #0 + LOADREGS(eqea,fp,{r4 - r8, fp, sp, pc}) + tst r2, #2 + beq Lexit + adcs r3, r3, r4, lsl #16 + strb r4, [r1], #1 + ldr r4, [r0], #4 + strb r4, [r1], #1 + adcs r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + b Lexit diff -ur --new-file old/linux/arch/arm/lib/delay.S new/linux/arch/arm/lib/delay.S --- old/linux/arch/arm/lib/delay.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/delay.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,43 @@ +/* + * linux/arch/arm/lib/delay.S + * + * Copyright (C) 1995, 1996 Russell King + */ +#include +#include + .text + +LC0: .word SYMBOL_NAME(loops_per_sec) + +ENTRY(udelay) + mov r2, #0x1000 + orr r2, r2, #0x00c6 + mul r1, r0, r2 + ldr r2, LC0 + ldr r2, [r2] + mov r1, r1, lsr #11 + mov r2, r2, lsr #11 + mul r0, r1, r2 + movs r0, r0, lsr #10 + RETINSTR(moveq,pc,lr) + +@ Delay routine +ENTRY(__delay) + subs r0, r0, #1 + RETINSTR(movcc,pc,lr) + subs r0, r0, #1 + RETINSTR(movcc,pc,lr) + subs r0, r0, #1 + RETINSTR(movcc,pc,lr) + subs r0, r0, #1 + RETINSTR(movcc,pc,lr) + subs r0, r0, #1 + RETINSTR(movcc,pc,lr) + subs r0, r0, #1 + RETINSTR(movcc,pc,lr) + subs r0, r0, #1 + RETINSTR(movcc,pc,lr) + subs r0, r0, #1 + bcs SYMBOL_NAME(__delay) + RETINSTR(mov,pc,lr) + diff -ur --new-file old/linux/arch/arm/lib/extractinfo.perl new/linux/arch/arm/lib/extractinfo.perl --- old/linux/arch/arm/lib/extractinfo.perl Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/extractinfo.perl Wed Jan 21 01:39:41 1998 @@ -0,0 +1,45 @@ +#!/usr/bin/perl + +$OBJDUMP=$ARGV[0]; + +sub swapdata { + local ($num) = @_; + + return substr($num, 6, 2).substr($num, 4, 2).substr ($num, 2, 2).substr ($num, 0, 2); +} + +open (DATA, $OBJDUMP.' --full-contents --section=.data getconsdata.o | grep \'^ 00\' |') || + die ('Cant objdump!'); +while () { + ($addr, $data0, $data1, $data2, $data3) = split (' '); + $dat[hex($addr)] = hex(&swapdata($data0)); + $dat[hex($addr)+4] = hex(&swapdata($data1)); + $dat[hex($addr)+8] = hex(&swapdata($data2)); + $dat[hex($addr)+12] = hex(&swapdata($data3)); +} +close (DATA); + +open (DATA, $OBJDUMP.' --syms getconsdata.o |') || die ('Cant objdump!'); +while () { + /elf32/ && ( $elf = 1 ); + /a.out/ && ( $aout = 1 ); + next if ($aout && ! / 07 /); + next if ($elf && ! (/^00...... g/ && /.data/)); + next if (!$aout && !$elf); + + ($addr, $flags, $sect, $a1, $a2, $a3, $name) = split (' ') if $aout; + $nam[hex($addr)] = substr($name, 1) if $aout; + if ($elf) { + chomp; + $addr = substr ($_, 0, 8); + $name = substr ($_, 32); + $nam[hex($addr)] = $name; + } +} +close (DATA); + +print "/*\n * *** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT! ***\n */\n"; +for ($i = 0; $i < hex($addr)+12; $i ++) { + print "unsigned long $nam[$i] = $dat[$i];\n" if $dat[$i]; + print "#define __HAS_$nam[$i]\n" if $dat[$i]; +} diff -ur --new-file old/linux/arch/arm/lib/floppydma.S new/linux/arch/arm/lib/floppydma.S --- old/linux/arch/arm/lib/floppydma.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/floppydma.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,57 @@ +/* + * linux/arch/arm/lib/floppydma.S + * + * Copyright (C) 1995, 1996 Russell King + */ +#include +#include + .text + + .global SYMBOL_NAME(floppy_fiqin_end) +ENTRY(floppy_fiqin_start) + subs r9, r9, #1 + ldrgtb r12, [r11, #-4] + ldrleb r12, [r11], #0 + strb r12, [r10], #1 + subs pc, lr, #4 +SYMBOL_NAME(floppy_fiqin_end): + + .global SYMBOL_NAME(floppy_fiqout_end) +ENTRY(floppy_fiqout_start) + subs r9, r9, #1 + ldrgeb r12, [r10], #1 + movlt r12, #0 + strleb r12, [r11], #0 + subles pc, lr, #4 + strb r12, [r11, #-4] + subs pc, lr, #4 +SYMBOL_NAME(floppy_fiqout_end): + +@ Params: +@ r0 = length +@ r1 = address +@ r2 = floppy port +@ Puts these into R9_fiq, R10_fiq, R11_fiq +ENTRY(floppy_fiqsetup) + mov ip, sp + stmfd sp!, {fp, ip, lr, pc} + sub fp, ip, #4 + MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ) @ disable FIQs, IRQs, FIQ mode + mov r0, r0 + mov r9, r0 + mov r10, r1 + mov r11, r2 + RESTOREMODE(r3) @ back to normal + mov r0, r0 + LOADREGS(ea,fp,{fp, sp, pc}) + +ENTRY(floppy_fiqresidual) + mov ip, sp + stmfd sp!, {fp, ip, lr, pc} + sub fp, ip, #4 + MODE(r3,ip,I_BIT|F_BIT|DEFAULT_FIQ) @ disable FIQs, IRQs, FIQ mode + mov r0, r0 + mov r0, r9 + RESTOREMODE(r3) + mov r0, r0 + LOADREGS(ea,fp,{fp, sp, pc}) diff -ur --new-file old/linux/arch/arm/lib/fp_support.c new/linux/arch/arm/lib/fp_support.c --- old/linux/arch/arm/lib/fp_support.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/fp_support.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,22 @@ +/* + * linux/arch/arm/lib/fp_support.c + * + * Copyright (C) 1995, 1996 Russell King + */ + +#include +#include + +extern void (*fp_save)(struct fp_soft_struct *); + +asmlinkage void fp_setup(void) +{ + struct task_struct *p; + + p = &init_task; + do { + fp_save(&p->tss.fpstate.soft); + p = p->next_task; + } + while (p != &init_task); +} diff -ur --new-file old/linux/arch/arm/lib/getconsdata.c new/linux/arch/arm/lib/getconsdata.c --- old/linux/arch/arm/lib/getconsdata.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/getconsdata.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/lib/getconsdata.c + * + * Copyright (C) 1995, 1996 Russell King + */ + +#include +#include +#include +#include +#include +#include + +#define OFF_TSK(n) (unsigned long)&(((struct task_struct *)0)->n) +#define OFF_MM(n) (unsigned long)&(((struct mm_struct *)0)->n) + +#ifdef KERNEL_DOMAIN +unsigned long kernel_domain = KERNEL_DOMAIN; +#endif +#ifdef USER_DOMAIN +unsigned long user_domain = USER_DOMAIN; +#endif +unsigned long addr_limit = OFF_TSK(addr_limit); +unsigned long tss_memmap = OFF_TSK(tss.memmap); +unsigned long mm = OFF_TSK(mm); +unsigned long pgd = OFF_MM(pgd); +unsigned long tss_save = OFF_TSK(tss.save); +unsigned long tss_fpesave = OFF_TSK(tss.fpstate.soft.save); +#if defined(CONFIG_CPU_ARM2) || defined(CONFIG_CPU_ARM3) +unsigned long tss_memcmap = OFF_TSK(tss.memcmap); +#endif diff -ur --new-file old/linux/arch/arm/lib/getconstants.c new/linux/arch/arm/lib/getconstants.c --- old/linux/arch/arm/lib/getconstants.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/getconstants.c Wed Jan 21 01:39:41 1998 @@ -0,0 +1,74 @@ +/* + * linux/arch/arm/lib/getconstants.c + * + * Copyright (C) 1995, 1996 Russell King + */ + +#include +#include +#include +#include + +void printdef(char *def, int no) +{ + printf("#define %s\t%d\n", def, no); +} + +#include "getconstants.h" + +int main() +{ + printf("/*\n * contants.h generated by getconstants\n * DO NOT EDIT!\n */\n"); + + printf("#define _current\t_%s\n", "current_set"); + +#ifdef _PAGE_PRESENT + printdef("PAGE_PRESENT", _PAGE_PRESENT); +#endif +#ifdef _PAGE_RW + printdef("PAGE_RW", _PAGE_RW); +#endif +#ifdef _PAGE_USER + printdef("PAGE_USER", _PAGE_USER); +#endif +#ifdef _PAGE_ACCESSED + printdef("PAGE_ACCESSED", _PAGE_ACCESSED); +#endif +#ifdef _PAGE_DIRTY + printdef("PAGE_DIRTY", _PAGE_DIRTY); +#endif +#ifdef _PAGE_READONLY + printdef("PAGE_READONLY", _PAGE_READONLY); +#endif +#ifdef _PAGE_NOT_USER + printdef("PAGE_NOT_USER", _PAGE_NOT_USER); +#endif +#ifdef _PAGE_OLD + printdef("PAGE_OLD", _PAGE_OLD); +#endif +#ifdef _PAGE_CLEAN + printdef("PAGE_CLEAN", _PAGE_CLEAN); +#endif + printdef("TSS_MEMMAP", (int)tss_memmap); + printdef("TSS_SAVE", (int)tss_save); +#ifdef __HAS_tss_memcmap + printdef("TSS_MEMCMAP", (int)tss_memcmap); +#endif +#ifdef __HAS_addr_limit + printdef("ADDR_LIMIT", (int)addr_limit); +#endif +#ifdef __HAS_kernel_domain + printdef("KERNEL_DOMAIN", kernel_domain); +#endif +#ifdef __HAS_user_domain + printdef("USER_DOMAIN", user_domain); +#endif + printdef("TSS_FPESAVE", (int)tss_fpesave); + printdef("MM", (int)mm); + printdef("PGD", (int)pgd); + + printf("#define KSWI_BASE 0x900000\n"); + printf("#define KSWI_SYS_BASE 0x9F0000\n"); + printf("#define SYS_ERROR0 0x9F0000\n"); + return 0; +} diff -ur --new-file old/linux/arch/arm/lib/getconstants.h new/linux/arch/arm/lib/getconstants.h --- old/linux/arch/arm/lib/getconstants.h Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/getconstants.h Wed Jan 21 01:39:41 1998 @@ -0,0 +1,17 @@ +/* + * *** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT! *** + */ +unsigned long addr_limit = 56; +#define __HAS_addr_limit +unsigned long tss_memmap = 640; +#define __HAS_tss_memmap +unsigned long mm = 1676; +#define __HAS_mm +unsigned long pgd = 8; +#define __HAS_pgd +unsigned long tss_save = 636; +#define __HAS_tss_save +unsigned long tss_fpesave = 492; +#define __HAS_tss_fpesave +unsigned long tss_memcmap = 644; +#define __HAS_tss_memcmap diff -ur --new-file old/linux/arch/arm/lib/io-acorn.S new/linux/arch/arm/lib/io-acorn.S --- old/linux/arch/arm/lib/io-acorn.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/io-acorn.S Sat Feb 21 03:28:21 1998 @@ -0,0 +1,215 @@ +/* + * linux/arch/arm/lib/io.S + * + * Copyright (C) 1995, 1996 Russell King + */ +#include /* for CONFIG_CPU_ARM2 and CONFIG_CPU_ARM3 */ +#include +#include +#include +#include + + .text + .align + +#define OUT(reg) \ + mov r8, reg, lsl $16 ;\ + orr r8, r8, r8, lsr $16 ;\ + str r8, [r3, r0, lsl $2] ;\ + mov r8, reg, lsr $16 ;\ + orr r8, r8, r8, lsl $16 ;\ + str r8, [r3, r0, lsl $2] + +#define IN(reg) \ + ldr reg, [r0] ;\ + and reg, reg, ip ;\ + ldr lr, [r0] ;\ + orr reg, reg, lr, lsl $16 + + .equ pcio_base_high, PCIO_BASE & 0xff000000 + .equ pcio_base_low, PCIO_BASE & 0x00ff0000 + .equ io_base_high, IO_BASE & 0xff000000 + .equ io_base_low, IO_BASE & 0x00ff0000 + + .equ addr_io_diff_hi, pcio_base_high - io_base_high + .equ addr_io_diff_lo, pcio_base_low - io_base_low + + .macro addr reg, off + tst \off, #0x80000000 + .if addr_io_diff_hi + movne \reg, #IO_BASE + moveq \reg, #pcio_base_high + .if pcio_base_low + addeq \reg, \reg, #pcio_base_low + .endif + .else + mov \reg, #IO_BASE + addeq \reg, \reg, #addr_io_diff_lo + .endif + .endm + +@ Purpose: read a block of data from a hardware register to memory. +@ Proto : insw(int from_port, void *to, int len_in_words); +@ Proto : inswb(int from_port, void *to, int len_in_bytes); +@ Notes : increment to + +ENTRY(insw) + mov r2, r2, lsl#1 +ENTRY(inswb) + mov ip, sp + stmfd sp!, {r4 - r10 ,fp ,ip ,lr ,pc} + sub fp, ip, #4 + addr r3, r0 + add r0, r3, r0, lsl #2 + tst r1, #3 + beq Linswok + tst r1, #1 + bne Linsw_notaligned + cmp r2, #1 + ldrge r4, [r0] + strgeb r4, [r1], #1 + movgt r4, r4, LSR#8 + strgtb r4, [r1], #1 + ldmleea fp, {r4 - r10, fp, sp, pc}^ + sub r2, r2, #2 +Linswok: mov ip, #0xFF + orr ip, ip, ip, lsl #8 +Linswlp: subs r2, r2, #64 + bmi Linsw_toosmall + IN(r3) + IN(r4) + IN(r5) + IN(r6) + IN(r7) + IN(r8) + IN(r9) + IN(r10) + stmia r1!, {r3 - r10} + IN(r3) + IN(r4) + IN(r5) + IN(r6) + IN(r7) + IN(r8) + IN(r9) + IN(r10) + stmia r1!, {r3 - r10} + bne Linswlp + LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) +Linsw_toosmall: + adds r2, r2, #32 + bmi Linsw_toosmall2 +Linsw2lp: IN(r3) + IN(r4) + IN(r5) + IN(r6) + IN(r7) + IN(r8) + IN(r9) + IN(r10) + stmia r1!, {r3 - r10} + LOADREGS(eqea, fp, {r4 - r10, fp, sp, pc}) + b Linsw_notaligned +Linsw_toosmall2: + add r2, r2, #32 +Linsw_notaligned: + cmp r2, #1 + LOADREGS(ltea, fp, {r4 - r10, fp, sp, pc}) + ldr r4, [r0] + strb r4, [r1], #1 + movgt r4, r4, LSR#8 + strgtb r4, [r1], #1 + subs r2, r2, #2 + bgt Linsw_notaligned + LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) + +@ Purpose: write a block of data from memory to a hardware register. +@ Proto : outsw(int to_reg, void *from, int len_in_words); +@ Proto : outswb(int to_reg, void *from, int len_in_bytes); +@ Notes : increments from + +ENTRY(outsw) + mov r2, r2, LSL#1 +ENTRY(outswb) + mov ip, sp + stmfd sp!, {r4 - r8, fp, ip, lr, pc} + sub fp, ip, #4 + addr r3, r0 + tst r1, #2 + beq 1f + ldr r4, [r1], #2 + mov r4, r4, lsl #16 + orr r4, r4, r4, lsr #16 + str r4, [r3, r0, lsl #2] + subs r2, r2, #2 + LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) +1: subs r2, r2, #32 + blt 2f + ldmia r1!, {r4, r5, r6, r7} + OUT(r4) + OUT(r5) + OUT(r6) + OUT(r7) + ldmia r1!, {r4, r5, r6, r7} + OUT(r4) + OUT(r5) + OUT(r6) + OUT(r7) + bne 1b + LOADREGS(ea, fp, {r4 - r8, fp, sp, pc}) +2: adds r2, r2, #32 + LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) +3: ldr r4, [r1],#2 + mov r4, r4, lsl#16 + orr r4, r4, r4, lsr#16 + str r4, [r3, r0, lsl#2] + subs r2, r2, #2 + bgt 3b + LOADREGS(ea, fp, {r4 - r8, fp, sp, pc}) + +@ Purpose: write a memc register +@ Proto : void memc_write(int register, int value); +@ Returns: nothing + +#if defined(CONFIG_CPU_ARM2) || defined(CONFIG_CPU_ARM3) +ENTRY(memc_write) + cmp r0, #7 + RETINSTR(movgt,pc,lr) + mov r0, r0, lsl #17 + mov r1, r1, lsl #15 + mov r1, r1, lsr #17 + orr r0, r0, r1, lsl #2 + add r0, r0, #0x03600000 + strb r0, [r0] + RETINSTR(mov,pc,lr) +#define CPSR2SPSR(rt) +#else +#define CPSR2SPSR(rt) \ + mrs rt, cpsr; \ + msr spsr, rt +#endif + +@ Purpose: call an expansion card loader to read bytes. +@ Proto : char read_loader(int offset, char *card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_read) + stmfd sp!, {r4 - r12, lr} + mov r11, r1 + mov r1, r0 + CPSR2SPSR(r0) + mov lr, pc + mov pc, r2 + LOADREGS(fd, sp!, {r4 - r12, pc}) + +@ Purpose: call an expansion card loader to reset the card +@ Proto : void read_loader(int card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_reset) + stmfd sp!, {r4 - r12, lr} + mov r11, r0 + CPSR2SPSR(r0) + mov lr, pc + add pc, r1, #8 + LOADREGS(fd, sp!, {r4 - r12, pc}) diff -ur --new-file old/linux/arch/arm/lib/io-ebsa110.S new/linux/arch/arm/lib/io-ebsa110.S --- old/linux/arch/arm/lib/io-ebsa110.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/io-ebsa110.S Wed Jan 21 01:39:41 1998 @@ -0,0 +1,149 @@ +/* + * linux/arch/arm/lib/io-ebsa.S + * + * Copyright (C) 1995, 1996 Russell King + */ +#include +#include + .text + .align + +#define OUT(reg) \ + mov r8, reg, lsl $16 ;\ + orr r8, r8, r8, lsr $16 ;\ + str r8, [r3, r0, lsl $2] ;\ + mov r8, reg, lsr $16 ;\ + orr r8, r8, r8, lsl $16 ;\ + str r8, [r3, r0, lsl $2] + +#define IN(reg) \ + ldr reg, [r0] ;\ + and reg, reg, ip ;\ + ldr lr, [r0] ;\ + orr reg, reg, lr, lsl $16 + +@ Purpose: read a block of data from a hardware register to memory. +@ Proto : insw(int from_port, void *to, int len_in_words); +@ Proto : inswb(int from_port, void *to, int len_in_bytes); +@ Notes : increment to + +ENTRY(insw) + mov r2, r2, lsl#1 +ENTRY(inswb) + mov ip, sp + stmfd sp!, {r4 - r10 ,fp ,ip ,lr ,pc} + sub fp, ip, #4 + cmp r0, #0x00c00000 + movge r3, #0 + movlt r3, #0xf0000000 + add r0, r3, r0, lsl #2 + tst r1, #3 + beq Linswok + tst r1, #1 + bne Linsw_notaligned + cmp r2, #1 + ldrge r4, [r0] + strgeb r4, [r1], #1 + movgt r4, r4, LSR#8 + strgtb r4, [r1], #1 + ldmleea fp, {r4 - r10, fp, sp, pc}^ + sub r2, r2, #2 +Linswok: mov ip, #0xFF + orr ip, ip, ip, lsl #8 +Linswlp: subs r2, r2, #64 + bmi Linsw_toosmall + IN(r3) + IN(r4) + IN(r5) + IN(r6) + IN(r7) + IN(r8) + IN(r9) + IN(r10) + stmia r1!, {r3 - r10} + IN(r3) + IN(r4) + IN(r5) + IN(r6) + IN(r7) + IN(r8) + IN(r9) + IN(r10) + stmia r1!, {r3 - r10} + bne Linswlp + LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) +Linsw_toosmall: + add r2, r2, #32 + bmi Linsw_toosmall2 +Linsw2lp: IN(r3) + IN(r4) + IN(r5) + IN(r6) + IN(r7) + IN(r8) + IN(r9) + IN(r10) + stmia r1!, {r3 - r10} + LOADREGS(eqea, fp, {r4 - r10, fp, sp, pc}) + b Linsw_notaligned +Linsw_toosmall2: + add r2, r2, #32 +Linsw_notaligned: + cmp r2, #1 + LOADREGS(ltea, fp, {r4 - r10, fp, sp, pc}) + ldr r4, [r0] + strb r4, [r1], #1 + movgt r4, r4, LSR#8 + strgtb r4, [r1], #1 + subs r2, r2, #2 + bgt Linsw_notaligned + LOADREGS(ea, fp, {r4 - r10, fp, sp, pc}) + +@ Purpose: write a block of data from memory to a hardware register. +@ Proto : outsw(int to_reg, void *from, int len_in_words); +@ Proto : outswb(int to_reg, void *from, int len_in_bytes); +@ Notes : increments from + +ENTRY(outsw) + mov r2, r2, LSL#1 +ENTRY(outswb) + mov ip, sp + stmfd sp!, {r4 - r8, fp, ip, lr, pc} + sub fp, ip, #4 + cmp r0, #0x00c00000 + movge r3, #0 + movlt r3, #0xf0000000 + tst r1, #2 + beq Loutsw32lp + ldr r4, [r1], #2 + mov r4, r4, lsl #16 + orr r4, r4, r4, lsr #16 + str r4, [r3, r0, lsl #2] + sub r2, r2, #2 + teq r2, #0 + LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) +Loutsw32lp: subs r2,r2,#32 + blt Loutsw_toosmall + ldmia r1!,{r4,r5,r6,r7} + OUT(r4) + OUT(r5) + OUT(r6) + OUT(r7) + ldmia r1!,{r4,r5,r6,r7} + OUT(r4) + OUT(r5) + OUT(r6) + OUT(r7) + LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) + b Loutsw32lp +Loutsw_toosmall: + adds r2,r2,#32 + LOADREGS(eqea, fp, {r4 - r8, fp, sp, pc}) +Llpx: ldr r4,[r1],#2 + mov r4,r4,LSL#16 + orr r4,r4,r4,LSR#16 + str r4,[r3,r0,LSL#2] + subs r2,r2,#2 + bgt Llpx + LOADREGS(ea, fp, {r4 - r8, fp, sp, pc}) + diff -ur --new-file old/linux/arch/arm/lib/ll_char_wr.S new/linux/arch/arm/lib/ll_char_wr.S --- old/linux/arch/arm/lib/ll_char_wr.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/ll_char_wr.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,157 @@ +/* + * linux/arch/arm/lib/ll_char_wr.S + * + * Copyright (C) 1995, 1996 Russell King. + * + * Speedups & 1bpp code (C) 1996 Philip Blundel & Russell King. + * + * 10-04-96 RMK Various cleanups & reduced register usage. + */ + +@ Regs: [] = corruptable +@ {} = used +@ () = dont use + +#include +#include + .text + +#define BOLD 0x01 +#define ITALIC 0x02 +#define UNDERLINE 0x04 +#define FLASH 0x08 +#define INVERSE 0x10 + +LC0: .word SYMBOL_NAME(bytes_per_char_h) + .word SYMBOL_NAME(video_size_row) + .word SYMBOL_NAME(cmap_80) + .word SYMBOL_NAME(con_charconvtable) + +ENTRY(ll_write_char) + stmfd sp!, {r4 - r7, lr} +@ +@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc) +@ + eor ip, r1, #UNDERLINE << 24 +/* + * calculate colours + */ + tst r1, #INVERSE << 24 + moveq r2, r1, lsr #8 + moveq r3, r1, lsr #16 + movne r2, r1, lsr #16 + movne r3, r1, lsr #8 + and r3, r3, #255 + and r2, r2, #255 +/* + * calculate offset into character table + */ + and r1, r1, #255 + mov r1, r1, lsl #3 +/* + * calculate offset required for each row [maybe I should make this an argument to this fn. + * Have to see what the register usage is like in the calling routines. + */ + adr r4, LC0 + ldmia r4, {r4, r5, r6, lr} + ldr r4, [r4] + ldr r5, [r5] +/* + * Go to resolution-dependent routine... + */ + cmp r4, #4 + blt Lrow1bpp + eor r2, r3, r2 @ Create eor mask to change colour from bg + orr r3, r3, r3, lsl #8 @ to fg. + orr r3, r3, r3, lsl #16 + add r0, r0, r5, lsl #3 @ Move to bottom of character + add r1, r1, #7 + ldrb r7, [r6, r1] + tst ip, #UNDERLINE << 24 + eoreq r7, r7, #255 + teq r4, #8 + beq Lrow8bpplp +@ +@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) +@ + orr r3, r3, r3, lsl #4 +Lrow4bpplp: ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + eor ip, r3, r7 + str ip, [r0, -r5]! + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r1, r1, #1 + ldrb r7, [r6, r1] + ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + eor ip, r3, r7 + str ip, [r0, -r5]! + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow4bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ +@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) +@ +Lrow8bpplp: mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 + eor r4, r3, r4 + ldr ip, [lr, ip, lsl #2] + mul ip, r2, ip + tst r1, #7 + eor ip, r3, ip + sub r0, r0, r5 + stmia r0, {r4, ip} + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r1, r1, #1 + ldrb r7, [r6, r1] + mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 + eor r4, r3, r4 + ldr ip, [lr, ip, lsl #2] + mul ip, r2, ip + tst r1, #7 + eor ip, r3, ip + sub r0, r0, r5 + stmia r0, {r4, ip} + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow8bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ +@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc) +@ +Lrow1bpp: add r6, r6, r1 + ldmia r6, {r4, r7} + tst ip, #INVERSE << 24 + mvnne r4, r4 + mvnne r7, r7 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + tst ip, #UNDERLINE << 24 + mvneq r7, r7 + strb r7, [r0], r5 + LOADREGS(fd, sp!, {r4 - r7, pc}) + + .bss +ENTRY(con_charconvtable) + .space 1024 diff -ur --new-file old/linux/arch/arm/lib/loaders.S new/linux/arch/arm/lib/loaders.S --- old/linux/arch/arm/lib/loaders.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/loaders.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,53 @@ +/* + * linux/arch/arm/lib/loaders.S + * + * This file contains the ROM loaders for buggy cards + */ +#include +#include + +/* + * Oak SCSI + */ + +ENTRY(oak_scsi_loader) + b Loak_scsi_read + .word 0 +Loak_scsi_reset: bic r10, r11, #0x00ff0000 + ldr r2, [r10] + RETINSTR(mov,pc,lr) + +Loak_scsi_read: mov r2, r1, lsr #3 + and r2, r2, #15 << 9 + bic r10, r11, #0x00ff0000 + ldr r2, [r10, r2] + mov r2, r1, lsl #20 + ldrb r0, [r11, r2, lsr #18] + ldr r2, [r10] + RETINSTR(mov,pc,lr) + +ENTRY(atomwide_serial_loader) + b Latomwide_serial_read + .word 0 +Latomwide_serial_reset: mov r2, #0x3c00 + strb r2, [r11, r2] + RETINSTR(mov,pc,lr) + +Latomwide_serial_read: cmp r1, #0x8000 + RETINSTR(movhi,pc,lr) + add r0, r1, #0x800 + mov r0, r0, lsr #11 + mov r3, #0x3c00 + strb r0, [r11, r3] + mov r2, r1, lsl #21 + ldrb r0, [r11, r2, lsr #19] + strb r2, [r11, r3] + RETINSTR(mov,pc,lr) + +/* + * Cards we don't know about yet + */ +ENTRY(noloader) + mov r0, r0 + mov r0, #0 + RETINSTR(mov,pc,lr) diff -ur --new-file old/linux/arch/arm/lib/memcpy.S new/linux/arch/arm/lib/memcpy.S --- old/linux/arch/arm/lib/memcpy.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/memcpy.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,312 @@ +/* + * linux/arch/arm/lib/segment.S + * + * Copyright (C) 1995, 1996 Russell King + * Except memcpy/memmove routine. + */ + +#include +#include + + .text +#define ENTER \ + mov ip,sp ;\ + stmfd sp!,{r4-r9,fp,ip,lr,pc} ;\ + sub fp,ip,#4 + +#define EXIT \ + LOADREGS(ea, fp, {r4 - r9, fp, sp, pc}) + +#define EXITEQ \ + LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc}) + +# Prototype: void memcpy(void *to,const void *from,unsigned long n); +# ARM3: cant use memcopy here!!! + +ENTRY(memcpy) +ENTRY(memmove) + ENTER + cmp r1, r0 + bcc 19f + subs r2, r2, #4 + blt 6f + ands ip, r0, #3 + bne 7f + ands ip, r1, #3 + bne 8f + +1: subs r2, r2, #8 + blt 5f + subs r2, r2, #0x14 + blt 3f +2: ldmia r1!,{r3 - r9, ip} + stmia r0!,{r3 - r9, ip} + subs r2, r2, #32 + bge 2b + cmn r2, #16 + ldmgeia r1!, {r3 - r6} + stmgeia r0!, {r3 - r6} + subge r2, r2, #0x10 +3: adds r2, r2, #0x14 +4: ldmgeia r1!, {r3 - r5} + stmgeia r0!, {r3 - r5} + subges r2, r2, #12 + bge 4b +5: adds r2, r2, #8 + blt 6f + subs r2, r2, #4 + ldrlt r3, [r1], #4 + strlt r3, [r0], #4 + ldmgeia r1!, {r3, r4} + stmgeia r0!, {r3, r4} + subge r2, r2, #4 + +6: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrgeb r3, [r1], #1 + strgeb r3, [r0], #1 + ldrgtb r3, [r1], #1 + strgtb r3, [r0], #1 + EXIT + +7: rsb ip, ip, #4 + cmp ip, #2 + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrgeb r3, [r1], #1 + strgeb r3, [r0], #1 + ldrgtb r3, [r1], #1 + strgtb r3, [r0], #1 + subs r2, r2, ip + blt 6b + ands ip, r1, #3 + beq 1b +8: bic r1, r1, #3 + ldr r7, [r1], #4 + cmp ip, #2 + bgt 15f + beq 11f + cmp r2, #12 + blt 10f + sub r2, r2, #12 +9: mov r3, r7, lsr #8 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 9b + adds r2, r2, #12 + blt 1b +10: mov r3, r7, lsr #8 + ldr r7, [r1], #4 + orr r3, r3, r7, lsl #24 + str r3, [r0], #4 + subs r2, r2, #4 + bge 10b + sub r1, r1, #3 + b 6b + +11: cmp r2, #12 + blt 13f /* */ + sub r2, r2, #12 +12: mov r3, r7, lsr #16 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #16 + mov r4, r4, lsr #16 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7,LSL#16 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 12b + adds r2, r2, #12 + blt 14f +13: mov r3, r7, lsr #16 + ldr r7, [r1], #4 + orr r3, r3, r7, lsl #16 + str r3, [r0], #4 + subs r2, r2, #4 + bge 13b +14: sub r1, r1, #2 + b 6b + +15: cmp r2, #12 + blt 17f + sub r2, r2, #12 +16: mov r3, r7, lsr #24 + ldmia r1!,{r4 - r7} + orr r3, r3, r4, lsl #8 + mov r4, r4, lsr #24 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 16b + adds r2, r2, #12 + blt 18f +17: mov r3, r7, lsr #24 + ldr r7, [r1], #4 + orr r3, r3, r7, lsl#8 + str r3, [r0], #4 + subs r2, r2, #4 + bge 17b +18: sub r1, r1, #1 + b 6b + + +19: add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt 24f + ands ip, r0, #3 + bne 25f + ands ip, r1, #3 + bne 26f + +20: subs r2, r2, #8 + blt 23f + subs r2, r2, #0x14 + blt 22f +21: ldmdb r1!, {r3 - r9, ip} + stmdb r0!, {r3 - r9, ip} + subs r2, r2, #32 + bge 21b +22: cmn r2, #16 + ldmgedb r1!, {r3 - r6} + stmgedb r0!, {r3 - r6} + subge r2, r2, #16 + adds r2, r2, #20 + ldmgedb r1!, {r3 - r5} + stmgedb r0!, {r3 - r5} + subge r2, r2, #12 +23: adds r2, r2, #8 + blt 24f + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + strlt r3, [r0, #-4]! + ldmgedb r1!, {r3, r4} + stmgedb r0!, {r3, r4} + subge r2, r2, #4 + +24: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrgeb r3, [r1, #-1]! + strgeb r3, [r0, #-1]! + ldrgtb r3, [r1, #-1]! + strgtb r3, [r0, #-1]! + EXIT + +25: cmp ip, #2 + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrgeb r3, [r1, #-1]! + strgeb r3, [r0, #-1]! + ldrgtb r3, [r1, #-1]! + strgtb r3, [r0, #-1]! + subs r2, r2, ip + blt 24b + ands ip, r1, #3 + beq 20b + +26: bic r1, r1, #3 + ldr r3, [r1], #0 + cmp ip, #2 + blt 34f + beq 30f + cmp r2, #12 + blt 28f + sub r2, r2, #12 +27: mov r7, r3, lsl #8 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #24 + mov r6, r6, lsl #8 + orr r6, r6, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r4, lsr #24 + mov r4, r4, lsl #8 + orr r4, r4, r3, lsr #24 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 27b + adds r2, r2, #12 + blt 29f +28: mov ip, r3, lsl #8 + ldr r3, [r1, #-4]! + orr ip, ip, r3, lsr #24 + str ip, [r0, #-4]! + subs r2, r2, #4 + bge 28b +29: add r1, r1, #3 + b 24b + +30: cmp r2, #12 + blt 32f + sub r2, r2, #12 +31: mov r7, r3, lsl #16 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #16 + mov r6, r6, lsl #16 + orr r6, r6, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r4, lsr #16 + mov r4, r4, lsl #16 + orr r4, r4, r3, lsr #16 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 31b + adds r2, r2, #12 + blt 33f +32: mov ip, r3, lsl #16 + ldr r3, [r1, #-4]! + orr ip, ip, r3, lsr #16 + str ip, [r0, #-4]! + subs r2, r2, #4 + bge 32b +33: add r1, r1, #2 + b 24b + +34: cmp r2, #12 + blt 36f + sub r2, r2, #12 +35: mov r7, r3, lsl #24 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, lsr #8 + mov r6, r6, lsl #24 + orr r6, r6, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r4, lsr #8 + mov r4, r4, lsl #24 + orr r4, r4, r3, lsr #8 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 35b + adds r2, r2, #12 + blt 37f +36: mov ip, r3, lsl #24 + ldr r3, [r1, #-4]! + orr ip, ip, r3, lsr #8 + str ip, [r0, #-4]! + subs r2, r2, #4 + bge 36b +37: add r1, r1, #1 + b 24b + + .align + diff -ur --new-file old/linux/arch/arm/lib/memfastset.S new/linux/arch/arm/lib/memfastset.S --- old/linux/arch/arm/lib/memfastset.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/memfastset.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,35 @@ +/* + * linux/arch/arm/lib/memfastset.S + * + * Copyright (C) 1995, 1996 Russell King + */ +#include +#include + .text +@ Prototype: void memsetl (unsigned long *d, unsigned long c, size_t n); + +ENTRY(memsetl) + stmfd sp!, {lr} + cmp r2, #16 + blt 5f + mov r3, r1 + mov ip, r1 + mov lr, r1 + subs r2, r2, #32 + bmi 2f +1: stmia r0!, {r1, r3, ip, lr} + stmia r0!, {r1, r3, ip, lr} + LOADREGS(eqfd, sp!, {pc}) + subs r2, r2, #32 + bpl 1b +2: adds r2, r2, #16 + bmi 4f +3: stmia r0!, {r1, r3, ip, lr} + LOADREGS(eqfd, sp!, {pc}) + subs r2, r2, #16 + bpl 3b +4: add r2, r2, #16 +5: subs r2, r2, #4 + strge r1, [r0], #4 + bgt 5b + LOADREGS(fd, sp!, {pc}) diff -ur --new-file old/linux/arch/arm/lib/string.S new/linux/arch/arm/lib/string.S --- old/linux/arch/arm/lib/string.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/string.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,139 @@ +/* + * linux/arch/arm/lib/string.S + * + * Copyright (C) 1995, 1996 Russell King + */ +#include +#include + .text +# Prototype: char *strrchr(const char *s,char c); + +@ r0 = pointer, r1 = length + .global memzero +memzero: stmfd sp!, {lr} + mov r2, #0 + mov r3, #0 + mov ip, #0 + mov lr, #0 +1: subs r1, r1, #4*8 + stmgeia r0!, {r2, r3, ip, lr} + stmgeia r0!, {r2, r3, ip, lr} + bgt 1b + LOADREGS(fd, sp!, {pc}) + + .global __page_memcpy +__page_memcpy: stmfd sp!, {r4, r5, lr} +1: subs r2, r2, #4*8 + ldmgeia r1!, {r3, r4, r5, ip} + stmgeia r0!, {r3, r4, r5, ip} + ldmgeia r1!, {r3, r4, r5, ip} + stmgeia r0!, {r3, r4, r5, ip} + bgt 1b + LOADREGS(fd, sp!, {r4, r5, pc}) + + .global memset +memset: mov r3, r0 + cmp r2, #16 + blt 6f + ands ip, r3, #3 + beq 1f + cmp ip, #2 + strltb r1, [r3], #1 @ Align destination + strleb r1, [r3], #1 + strb r1, [r3], #1 + rsb ip, ip, #4 + sub r2, r2, ip +1: orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + cmp r2, #256 + blt 4f + stmfd sp!, {r4, r5, lr} + mov r4, r1 + mov r5, r1 + mov lr, r1 + mov ip, r2, lsr #6 + sub r2, r2, ip, lsl #6 +2: stmia r3!, {r1, r4, r5, lr} @ 64 bytes at a time. + stmia r3!, {r1, r4, r5, lr} + stmia r3!, {r1, r4, r5, lr} + stmia r3!, {r1, r4, r5, lr} + subs ip, ip, #1 + bne 2b + teq r2, #0 + LOADREGS(eqfd, sp!, {r4, r5, pc}) @ Now <64 bytes to go. + tst r2, #32 + stmneia r3!, {r1, r4, r5, lr} + stmneia r3!, {r1, r4, r5, lr} + tst r2, #16 + stmneia r3!, {r1, r4, r5, lr} + ldmia sp!, {r4, r5} +3: tst r2, #8 + stmneia r3!, {r1, lr} + tst r2, #4 + strne r1, [r3], #4 + tst r2, #2 + strneb r1, [r3], #1 + strneb r1, [r3], #1 + tst r2, #1 + strneb r1, [r3], #1 + LOADREGS(fd, sp!, {pc}) + +4: movs ip, r2, lsr #3 + beq 3b + sub r2, r2, ip, lsl #3 + stmfd sp!, {lr} + mov lr, r1 + subs ip, ip, #4 +5: stmgeia r3!, {r1, lr} + stmgeia r3!, {r1, lr} + stmgeia r3!, {r1, lr} + stmgeia r3!, {r1, lr} + subges ip, ip, #4 + bge 5b + tst ip, #2 + stmneia r3!, {r1, lr} + stmneia r3!, {r1, lr} + tst ip, #1 + stmneia r3!, {r1, lr} + teq r2, #0 + LOADREGS(eqfd, sp!, {pc}) + b 3b + +6: subs r2, r2, #1 + strgeb r1, [r3], #1 + bgt 6b + RETINSTR(mov, pc, lr) + +ENTRY(strrchr) + stmfd sp!, {lr} + mov r3, #0 +1: ldrb r2, [r0], #1 + teq r2, r1 + moveq r3, r0 + teq r2, #0 + bne 1b + mov r0, r3 + LOADREGS(fd, sp!, {pc}) + +ENTRY(strchr) + stmfd sp!,{lr} + mov r3, #0 +1: ldrb r2, [r0], #1 + teq r2, r1 + teqne r2, #0 + bne 1b + teq r2, #0 + moveq r0, #0 + subne r0, r0, #1 + LOADREGS(fd, sp!, {pc}) + +ENTRY(memchr) + stmfd sp!, {lr} +1: ldrb r3, [r0], #1 + teq r3, r1 + beq 2f + subs r2, r2, #1 + bpl 1b +2: movne r0, #0 + subeq r0, r0, #1 + LOADREGS(fd, sp!, {pc}) diff -ur --new-file old/linux/arch/arm/lib/system.S new/linux/arch/arm/lib/system.S --- old/linux/arch/arm/lib/system.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/system.S Sat Feb 21 03:28:21 1998 @@ -0,0 +1,20 @@ +/* + * linux/arch/arm/lib/system.S + * + * Copyright (C) 1995, 1996 Russell King + * + * 07/06/96: Now support tasks running in SVC mode. + */ +#include +#include + + .text + +ENTRY(abort) + adr r0, .abort_msg + mov r1, lr + b SYMBOL_NAME(panic) + +.abort_msg: .ascii "Eek! Got to an abort() from %p! " + .ascii "(Please report to rmk@ecs.soton.ac.uk)\n\0" + .align diff -ur --new-file old/linux/arch/arm/lib/testm.c new/linux/arch/arm/lib/testm.c --- old/linux/arch/arm/lib/testm.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/testm.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,81 @@ +char buffer[1036]; +char buffer2[1036]; + +int main () +{ + char *p; + int i, o, o2, l; + + printf ("Testing memset\n"); + for (l = 1; l < 1020; l ++) { + for (o = 0; o < 4; o++) { + p = buffer + o + 4; + for (i = 0; i < l + 12; i++) + buffer[i] = 0x55; + + memset (p, 0xaa, l); + + for (i = 0; i < l; i++) + if (p[i] != 0xaa) + printf ("Error: %X+%d\n", p, i); + if (p[-1] != 0x55 || p[-2] != 0x55 || p[-3] != 0x55 || p[-4] != 0x55) + printf ("Error before %X\n", p); + if (p[l] != 0x55 || p[l+1] != 0x55 || p[l+2] != 0x55 || p[l+3] != 0x55) + printf ("Error at end: %p: %02X %02X %02X %02X\n", p+l, p[l], p[l+1], p[l+2], p[l+3]); + } + } + + printf ("Testing memcpy s > d\n"); + for (l = 1; l < 1020; l++) { + for (o = 0; o < 4; o++) { + for (o2 = 0; o2 < 4; o2++) { + char *d, *s; + + for (i = 0; i < l + 12; i++) + buffer[i] = (i & 0x3f) + 0x40; + for (i = 0; i < 1036; i++) + buffer2[i] = 0; + + s = buffer + o; + d = buffer2 + o2 + 4; + + memcpy (d, s, l); + + for (i = 0; i < l; i++) + if (s[i] != d[i]) + printf ("Error at %X+%d -> %X+%d (%02X != %02X)\n", s, i, d, i, s[i], d[i]); + if (d[-1] || d[-2] || d[-3] || d[-4]) + printf ("Error before %X\n", d); + if (d[l] || d[l+1] || d[l+2] || d[l+3]) + printf ("Error after %X\n", d+l); + } + } + } + + printf ("Testing memcpy s < d\n"); + for (l = 1; l < 1020; l++) { + for (o = 0; o < 4; o++) { + for (o2 = 0; o2 < 4; o2++) { + char *d, *s; + + for (i = 0; i < l + 12; i++) + buffer2[i] = (i & 0x3f) + 0x40; + for (i = 0; i < 1036; i++) + buffer[i] = 0; + + s = buffer2 + o; + d = buffer + o2 + 4; + + memcpy (d, s, l); + + for (i = 0; i < l; i++) + if (s[i] != d[i]) + printf ("Error at %X+%d -> %X+%d (%02X != %02X)\n", s, i, d, i, s[i], d[i]); + if (d[-1] || d[-2] || d[-3] || d[-4]) + printf ("Error before %X\n", d); + if (d[l] || d[l+1] || d[l+2] || d[l+3]) + printf ("Error after %X\n", d+l); + } + } + } +} diff -ur --new-file old/linux/arch/arm/lib/uaccess-armo.S new/linux/arch/arm/lib/uaccess-armo.S --- old/linux/arch/arm/lib/uaccess-armo.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/uaccess-armo.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,230 @@ +/* + * arch/arm/lib/uaccess-armo.S + * + * Copyright (C) 1998 Russell King + * + * Note! Some code fragments found in here have a special calling + * convention - they are not APCS compliant! + */ +#include +#include + + .text + +#define USER(x...) \ +9999: x; \ + .section __ex_table,"a"; \ + .align 3; \ + .long 9999b,9001f; \ + .previous + + .globl SYMBOL_NAME(uaccess_user) +SYMBOL_NAME(uaccess_user): + .word uaccess_user_put_byte + .word uaccess_user_get_byte + .word uaccess_user_put_half + .word uaccess_user_get_half + .word uaccess_user_put_word + .word uaccess_user_get_word + .word __arch_copy_from_user + .word __arch_copy_to_user + .word __arch_clear_user + .word __arch_strncpy_from_user + .word __arch_strlen_user + + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_user_put_byte: + stmfd sp!, {lr} +USER( strbt r0, [r1]) + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_user_put_half: + stmfd sp!, {lr} +USER( strbt r0, [r1], #1) + mov r0, r0, lsr #8 +USER( strbt r0, [r1]) + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_user_put_word: + stmfd sp!, {lr} +USER( strt r0, [r1]) + ldmfd sp!, {pc}^ + +9001: mov r2, #-EFAULT + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_user_get_byte: + stmfd sp!, {lr} +USER( ldrbt r0, [r0]) + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_user_get_half: + stmfd sp!, {lr} +USER( ldrt r0, [r0]) + mov r0, r0, lsl #16 + mov r0, r0, lsr #16 + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_user_get_word: + stmfd sp!, {lr} +USER( ldrt r0, [r0]) + ldmfd sp!, {pc}^ + +9001: mov r1, #-EFAULT + ldmfd sp!, {pc}^ + + + + .globl SYMBOL_NAME(uaccess_kernel) +SYMBOL_NAME(uaccess_kernel): + .word uaccess_kernel_put_byte + .word uaccess_kernel_get_byte + .word uaccess_kernel_put_half + .word uaccess_kernel_get_half + .word uaccess_kernel_put_word + .word uaccess_kernel_get_word + .word uaccess_kernel_copy + .word uaccess_kernel_copy + .word uaccess_kernel_clear + .word uaccess_kernel_strncpy_from + .word uaccess_kernel_strlen + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_kernel_put_byte: + stmfd sp!, {lr} + strb r0, [r1] + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_kernel_put_half: + stmfd sp!, {lr} + strb r0, [r1] + mov r0, r0, lsr #8 + strb r0, [r1, #1] + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_kernel_put_word: + stmfd sp!, {lr} + str r0, [r1] + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_kernel_get_byte: + stmfd sp!, {lr} + ldrb r0, [r0] + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_kernel_get_half: + stmfd sp!, {lr} + ldr r0, [r0] + mov r0, r0, lsl #16 + mov r0, r0, lsr #16 + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_kernel_get_word: + stmfd sp!, {lr} + ldr r0, [r0] + ldmfd sp!, {pc}^ + + +/* Prototype: int uaccess_kernel_copy(void *to, const char *from, size_t n) + * Purpose : copy a block to kernel memory from kernel memory + * Params : to - kernel memory + * : from - kernel memory + * : n - number of bytes to copy + * Returns : Number of bytes NOT copied. + */ +uaccess_kernel_copy: + stmfd sp!, {lr} + bl SYMBOL_NAME(memcpy) + mov r0, #0 + ldmfd sp!, {pc}^ + +/* Prototype: int uaccess_kernel_clear(void *addr, size_t sz) + * Purpose : clear some kernel memory + * Params : addr - kernel memory address to clear + * : sz - number of bytes to clear + * Returns : number of bytes NOT cleared + */ +uaccess_kernel_clear: + stmfd sp!, {lr} + mov r2, #0 + cmp r1, #4 + blt 2f + ands ip, r0, #3 + beq 1f + cmp ip, #1 + strb r2, [r0], #1 + strleb r2, [r0], #1 + strltb r2, [r0], #1 + rsb ip, ip, #4 + sub r1, r1, ip @ 7 6 5 4 3 2 1 +1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 + bmi 2f + str r2, [r0], #4 + str r2, [r0], #4 + b 1b +2: adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 + strpl r2, [r0], #4 + tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x + strneb r2, [r0], #1 + strneb r2, [r0], #1 + tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 + strneb r2, [r0], #1 + mov r0, #0 + ldmfd sp!, {pc}^ + +/* Prototype: size_t uaccess_kernel_strncpy_from(char *dst, char *src, size_t len) + * Purpose : copy a string from kernel memory to kernel memory + * Params : dst - kernel memory destination + * : src - kernel memory source + * : len - maximum length of string + * Returns : number of characters copied + */ +uaccess_kernel_strncpy_from: + stmfd sp!, {lr} + mov ip, r2 +1: subs r2, r2, #1 + bmi 2f + ldrb r3, [r1], #1 + strb r3, [r0], #1 + teq r3, #0 + bne 1b +2: subs r0, ip, r2 + ldmfd sp!, {pc}^ + +/* Prototype: int uaccess_kernel_strlen(char *str) + * Purpose : get length of a string in kernel memory + * Params : str - address of string in kernel memory + * Returns : length of string *including terminator*, or zero on error + */ +uaccess_kernel_strlen: + stmfd sp!, {lr} + mov r2, r0 +1: ldrb r1, [r0], #1 + teq r1, #0 + bne 1b + sub r0, r0, r2 + ldmfd sp!, {pc}^ + diff -ur --new-file old/linux/arch/arm/lib/uaccess.S new/linux/arch/arm/lib/uaccess.S --- old/linux/arch/arm/lib/uaccess.S Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/lib/uaccess.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,631 @@ +/* + * linux/arch/arm/lib/uaccess.S + * + * Copyright (C) 1995, 1996,1997,1998 Russell King + * + * Routines to block copy data to/from user memory + * These are highly optimised both for the 4k page size + * and for various alignments. + */ +#include +#include +#include +#include + + .text + +#define USER(x...) \ +9999: x; \ + .section __ex_table,"a"; \ + .align 3; \ + .long 9999b,9001f; \ + .previous + +#define PAGE_SHIFT 12 + +/* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n) + * Purpose : copy a block to user memory from kernel memory + * Params : to - user memory + * : from - kernel memory + * : n - number of bytes to copy + * Returns : Number of bytes NOT copied. + */ + +.c2u_dest_not_aligned: + rsb ip, ip, #4 + cmp ip, #2 + ldrb r3, [r1], #1 +USER( strbt r3, [r0], #1) // May fault + ldrgeb r3, [r1], #1 +USER( strgebt r3, [r0], #1) // May fault + ldrgtb r3, [r1], #1 +USER( strgtbt r3, [r0], #1) // May fault + sub r2, r2, ip + b .c2u_dest_aligned + +ENTRY(__arch_copy_to_user) + stmfd sp!, {r2, r4 - r7, lr} + cmp r2, #4 + blt .c2u_not_enough + ands ip, r0, #3 + bne .c2u_dest_not_aligned +.c2u_dest_aligned: + + ands ip, r1, #3 + bne .c2u_src_not_aligned +/* + * Seeing as there has to be at least 8 bytes to copy, we can + * copy one word, and force a user-mode page fault... + */ + +.c2u_0fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_0nowords + ldr r3, [r1], #4 +USER( strt r3, [r0], #4) // May fault + mov ip, r0, lsl #32 - PAGE_SHIFT // On each page, use a ld/st??t instruction + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .c2u_0fupi +/* + * ip = max no. of bytes to copy before needing another "strt" insn + */ + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #32 + blt .c2u_0rem8lp + +.c2u_0cpy8lp: ldmia r1!, {r3 - r6} + stmia r0!, {r3 - r6} // Shouldn't fault + ldmia r1!, {r3 - r6} + stmia r0!, {r3 - r6} // Shouldn't fault + subs ip, ip, #32 + bpl .c2u_0cpy8lp +.c2u_0rem8lp: cmn ip, #16 + ldmgeia r1!, {r3 - r6} + stmgeia r0!, {r3 - r6} // Shouldn't fault + tst ip, #8 + ldmneia r1!, {r3 - r4} + stmneia r0!, {r3 - r4} // Shouldn't fault + tst ip, #4 + ldrne r3, [r1], #4 + strnet r3, [r0], #4 // Shouldn't fault + ands ip, ip, #3 + beq .c2u_0fupi +.c2u_0nowords: teq ip, #0 + beq .c2u_finished +.c2u_nowords: cmp ip, #2 + ldrb r3, [r1], #1 +USER( strbt r3, [r0], #1) // May fault + ldrgeb r3, [r1], #1 +USER( strgebt r3, [r0], #1) // May fault + ldrgtb r3, [r1], #1 +USER( strgtbt r3, [r0], #1) // May fault + b .c2u_finished + +.c2u_not_enough: + movs ip, r2 + bne .c2u_nowords +.c2u_finished: mov r0, #0 + LOADREGS(fd,sp!,{r2, r4 - r7, pc}) + +.c2u_src_not_aligned: + bic r1, r1, #3 + ldr r7, [r1], #4 + cmp ip, #2 + bgt .c2u_3fupi + beq .c2u_2fupi +.c2u_1fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_1nowords + mov r3, r7, lsr #8 + ldr r7, [r1], #4 + orr r3, r3, r7, lsl #24 +USER( strt r3, [r0], #4) // May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .c2u_1fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_1rem8lp + +.c2u_1cpy8lp: mov r3, r7, lsr #8 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + stmia r0!, {r3 - r6} // Shouldn't fault + subs ip, ip, #16 + bpl .c2u_1cpy8lp +.c2u_1rem8lp: tst ip, #8 + movne r3, r7, lsr #8 + ldmneia r1!, {r4, r7} + orrne r3, r3, r4, lsl #24 + movne r4, r4, lsr #8 + orrne r4, r4, r7, lsl #24 + stmneia r0!, {r3 - r4} // Shouldn't fault + tst ip, #4 + movne r3, r7, lsr #8 + ldrne r7, [r1], #4 + orrne r3, r3, r7, lsl #24 + strnet r3, [r0], #4 // Shouldn't fault + ands ip, ip, #3 + beq .c2u_1fupi +.c2u_1nowords: mov r3, r7, lsr #8 + teq ip, #0 + beq .c2u_finished + cmp ip, #2 +USER( strbt r3, [r0], #1) // May fault + movge r3, r3, lsr #8 +USER( strgebt r3, [r0], #1) // May fault + movgt r3, r3, lsr #8 +USER( strgtbt r3, [r0], #1) // May fault + b .c2u_finished + +.c2u_2fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_2nowords + mov r3, r7, lsr #16 + ldr r7, [r1], #4 + orr r3, r3, r7, lsl #16 +USER( strt r3, [r0], #4) // May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .c2u_2fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_2rem8lp + +.c2u_2cpy8lp: mov r3, r7, lsr #16 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #16 + mov r4, r4, lsr #16 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7, lsl #16 + stmia r0!, {r3 - r6} // Shouldn't fault + subs ip, ip, #16 + bpl .c2u_2cpy8lp +.c2u_2rem8lp: tst ip, #8 + movne r3, r7, lsr #16 + ldmneia r1!, {r4, r7} + orrne r3, r3, r4, lsl #16 + movne r4, r4, lsr #16 + orrne r4, r4, r7, lsl #16 + stmneia r0!, {r3 - r4} // Shouldn't fault + tst ip, #4 + movne r3, r7, lsr #16 + ldrne r7, [r1], #4 + orrne r3, r3, r7, lsl #16 + strnet r3, [r0], #4 // Shouldn't fault + ands ip, ip, #3 + beq .c2u_2fupi +.c2u_2nowords: mov r3, r7, lsr #16 + teq ip, #0 + beq .c2u_finished + cmp ip, #2 +USER( strbt r3, [r0], #1) // May fault + movge r3, r3, lsr #8 +USER( strgebt r3, [r0], #1) // May fault + ldrgtb r3, [r1], #0 +USER( strgtbt r3, [r0], #1) // May fault + b .c2u_finished + +.c2u_3fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_3nowords + mov r3, r7, lsr #24 + ldr r7, [r1], #4 + orr r3, r3, r7, lsl #8 +USER( strt r3, [r0], #4) // May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .c2u_3fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_3rem8lp + +.c2u_3cpy8lp: mov r3, r7, lsr #24 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, lsl #8 + mov r4, r4, lsr #24 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + stmia r0!, {r3 - r6} // Shouldn't fault + subs ip, ip, #16 + bpl .c2u_3cpy8lp +.c2u_3rem8lp: tst ip, #8 + movne r3, r7, lsr #24 + ldmneia r1!, {r4, r7} + orrne r3, r3, r4, lsl #8 + movne r4, r4, lsr #24 + orrne r4, r4, r7, lsl #8 + stmneia r0!, {r3 - r4} // Shouldn't fault + tst ip, #4 + movne r3, r7, lsr #24 + ldrne r7, [r1], #4 + orrne r3, r3, r7, lsl #8 + strnet r3, [r0], #4 // Shouldn't fault + ands ip, ip, #3 + beq .c2u_3fupi +.c2u_3nowords: mov r3, r7, lsr #24 + teq ip, #0 + beq .c2u_finished + cmp ip, #2 +USER( strbt r3, [r0], #1) // May fault + ldrge r3, [r1], #0 +USER( strgebt r3, [r0], #1) // May fault + movgt r3, r3, lsr #8 +USER( strgtbt r3, [r0], #1) // May fault + b .c2u_finished + + .section .fixup,"ax" + .align 0 +9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc}) + .previous + + + +/* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n); + * Purpose : copy a block from user memory to kernel memory + * Params : to - kernel memory + * : from - user memory + * : n - number of bytes to copy + * Returns : Number of bytes NOT copied. + */ +.cfu_dest_not_aligned: + rsb ip, ip, #4 + cmp ip, #2 +USER( ldrbt r3, [r1], #1) // May fault + strb r3, [r0], #1 +USER( ldrgebt r3, [r1], #1) // May fault + strgeb r3, [r0], #1 +USER( ldrgtbt r3, [r1], #1) // May fault + strgtb r3, [r0], #1 + sub r2, r2, ip + b .cfu_dest_aligned + +ENTRY(__arch_copy_from_user) + stmfd sp!, {r2, r4 - r7, lr} + cmp r2, #4 + blt .cfu_not_enough + ands ip, r0, #3 + bne .cfu_dest_not_aligned +.cfu_dest_aligned: + ands ip, r1, #3 + bne .cfu_src_not_aligned +/* + * Seeing as there has to be at least 8 bytes to copy, we can + * copy one word, and force a user-mode page fault... + */ + +.cfu_0fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_0nowords +USER( ldrt r3, [r1], #4) + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT // On each page, use a ld/st??t instruction + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .cfu_0fupi +/* + * ip = max no. of bytes to copy before needing another "strt" insn + */ + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #32 + blt .cfu_0rem8lp + +.cfu_0cpy8lp: ldmia r1!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} + ldmia r1!, {r3 - r6} // Shouldn't fault + stmia r0!, {r3 - r6} + subs ip, ip, #32 + bpl .cfu_0cpy8lp +.cfu_0rem8lp: cmn ip, #16 + ldmgeia r1!, {r3 - r6} // Shouldn't fault + stmgeia r0!, {r3 - r6} + tst ip, #8 + ldmneia r1!, {r3 - r4} // Shouldn't fault + stmneia r0!, {r3 - r4} + tst ip, #4 + ldrnet r3, [r1], #4 // Shouldn't fault + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_0fupi +.cfu_0nowords: teq ip, #0 + beq .cfu_finished +.cfu_nowords: cmp ip, #2 +USER( ldrbt r3, [r1], #1) // May fault + strb r3, [r0], #1 +USER( ldrgebt r3, [r1], #1) // May fault + strgeb r3, [r0], #1 +USER( ldrgtbt r3, [r1], #1) // May fault + strgtb r3, [r0], #1 + b .cfu_finished + +.cfu_not_enough: + movs ip, r2 + bne .cfu_nowords +.cfu_finished: mov r0, #0 + LOADREGS(fd,sp!,{r2, r4 - r7, pc}) + +.cfu_src_not_aligned: + bic r1, r1, #3 +USER( ldrt r7, [r1], #4) // May fault + cmp ip, #2 + bgt .cfu_3fupi + beq .cfu_2fupi +.cfu_1fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_1nowords + mov r3, r7, lsr #8 +USER( ldrt r7, [r1], #4) // May fault + orr r3, r3, r7, lsl #24 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .cfu_1fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_1rem8lp + +.cfu_1cpy8lp: mov r3, r7, lsr #8 + ldmia r1!, {r4 - r7} // Shouldn't fault + orr r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r6, lsl #24 + mov r6, r6, lsr #8 + orr r6, r6, r7, lsl #24 + stmia r0!, {r3 - r6} + subs ip, ip, #16 + bpl .cfu_1cpy8lp +.cfu_1rem8lp: tst ip, #8 + movne r3, r7, lsr #8 + ldmneia r1!, {r4, r7} // Shouldn't fault + orrne r3, r3, r4, lsl #24 + movne r4, r4, lsr #8 + orrne r4, r4, r7, lsl #24 + stmneia r0!, {r3 - r4} + tst ip, #4 + movne r3, r7, lsr #8 +USER( ldrnet r7, [r1], #4) // May fault + orrne r3, r3, r7, lsl #24 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_1fupi +.cfu_1nowords: mov r3, r7, lsr #8 + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 + movge r3, r3, lsr #8 + strgeb r3, [r0], #1 + movgt r3, r3, lsr #8 + strgtb r3, [r0], #1 + b .cfu_finished + +.cfu_2fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_2nowords + mov r3, r7, lsr #16 +USER( ldrt r7, [r1], #4) // May fault + orr r3, r3, r7, lsl #16 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .cfu_2fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_2rem8lp + +.cfu_2cpy8lp: mov r3, r7, lsr #16 + ldmia r1!, {r4 - r7} // Shouldn't fault + orr r3, r3, r4, lsl #16 + mov r4, r4, lsr #16 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r6, lsl #16 + mov r6, r6, lsr #16 + orr r6, r6, r7, lsl #16 + stmia r0!, {r3 - r6} + subs ip, ip, #16 + bpl .cfu_2cpy8lp +.cfu_2rem8lp: tst ip, #8 + movne r3, r7, lsr #16 + ldmneia r1!, {r4, r7} // Shouldn't fault + orrne r3, r3, r4, lsl #16 + movne r4, r4, lsr #16 + orrne r4, r4, r7, lsl #16 + stmneia r0!, {r3 - r4} + tst ip, #4 + movne r3, r7, lsr #16 +USER( ldrnet r7, [r1], #4) // May fault + orrne r3, r3, r7, lsl #16 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_2fupi +.cfu_2nowords: mov r3, r7, lsr #16 + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 + movge r3, r3, lsr #8 + strgeb r3, [r0], #1 +USER( ldrgtbt r3, [r1], #0) // May fault + strgtb r3, [r0], #1 + b .cfu_finished + +.cfu_3fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_3nowords + mov r3, r7, lsr #24 +USER( ldrt r7, [r1], #4) // May fault + orr r3, r3, r7, lsl #8 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .cfu_3fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_3rem8lp + +.cfu_3cpy8lp: mov r3, r7, lsr #24 + ldmia r1!, {r4 - r7} // Shouldn't fault + orr r3, r3, r4, lsl #8 + mov r4, r4, lsr #24 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r6, lsl #8 + mov r6, r6, lsr #24 + orr r6, r6, r7, lsl #8 + stmia r0!, {r3 - r6} + subs ip, ip, #16 + bpl .cfu_3cpy8lp +.cfu_3rem8lp: tst ip, #8 + movne r3, r7, lsr #24 + ldmneia r1!, {r4, r7} // Shouldn't fault + orrne r3, r3, r4, lsl #8 + movne r4, r4, lsr #24 + orrne r4, r4, r7, lsl #8 + stmneia r0!, {r3 - r4} + tst ip, #4 + movne r3, r7, lsr #24 +USER( ldrnet r7, [r1], #4) // May fault + orrne r3, r3, r7, lsl #8 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_3fupi +.cfu_3nowords: mov r3, r7, lsr #24 + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 +USER( ldrget r3, [r1], #0) // May fault + strgeb r3, [r0], #1 + movgt r3, r3, lsr #8 + strgtb r3, [r0], #1 + b .cfu_finished + + .section .fixup,"ax" + .align 0 +9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc}) + .previous + +/* Prototype: int __arch_clear_user(void *addr, size_t sz) + * Purpose : clear some user memory + * Params : addr - user memory address to clear + * : sz - number of bytes to clear + * Returns : number of bytes NOT cleared + */ +ENTRY(__arch_clear_user) + stmfd sp!, {r1, lr} + mov r2, #0 + cmp r1, #4 + blt 2f + ands ip, r0, #3 + beq 1f + cmp ip, #1 +USER( strbt r2, [r0], #1) +USER( strlebt r2, [r0], #1) +USER( strltbt r2, [r0], #1) + rsb ip, ip, #4 + sub r1, r1, ip @ 7 6 5 4 3 2 1 +1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 +USER( strplt r2, [r0], #4) +USER( strplt r2, [r0], #4) + bpl 1b +2: adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 +USER( strplt r2, [r0], #4) + tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x +USER( strnebt r2, [r0], #1) +USER( strnebt r2, [r0], #1) + tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 +USER( strnebt r2, [r0], #1) + mov r0, #0 + LOADREGS(fd,sp!, {r1, pc}) + + .section .fixup,"ax" + .align 0 +9001: LOADREGS(fd,sp!, {r0, pc}) + .previous + +/* Prototype: int __arch_strlen_user(char *str) + * Purpose : get length of a string in user memory + * Params : str - address of string in user memory + * Returns : length of string *including terminator*, or zero on error + */ +ENTRY(__arch_strlen_user) + stmfd sp!, {lr} + mov r2, r0 +1: +USER( ldrbt r1, [r0], #1) + teq r1, #0 + bne 1b + sub r0, r0, r2 + LOADREGS(fd,sp!, {pc}) + + .section .fixup,"ax" + .align 0 +9001: mov r0, #0 + LOADREGS(fd,sp!,{pc}) + .previous + +/* Prototype: size_t __arch_strncpy_from_user(char *dst, char *src, size_t len) + * Purpose : copy a string from user memory to kernel memory + * Params : dst - kernel memory destination + * : src - user memory source + * : len - maximum length of string + * Returns : number of characters copied + */ +ENTRY(__arch_strncpy_from_user) + stmfd sp!, {lr} + mov ip, r2 +1: subs r2, r2, #1 + bmi 2f +USER( ldrbt r3, [r1], #1) + strb r3, [r0], #1 + teq r3, #0 + bne 1b +2: subs r0, ip, r2 + LOADREGS(fd,sp!, {pc}) + + .section .fixup,"ax" + .align 0 +9001: mov r0, #-EFAULT + LOADREGS(fd,sp!, {pc}) + .previous + + .align + diff -ur --new-file old/linux/arch/arm/mm/Makefile new/linux/arch/arm/mm/Makefile --- old/linux/arch/arm/mm/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/Makefile Wed Jan 21 01:39:42 1998 @@ -0,0 +1,36 @@ +# +# Makefile for the linux arm-specific parts of the memory manager. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := mm.o +O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(MACHINE).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 +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 + +.PHONY: ../lib/constants.h +../lib/constants.h: + @$(MAKE) -C ../lib constants.h + +%.o: %.S +ifndef $(CONFIG_BINUTILS_NEW) + $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.s + $(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.s + $(RM) ..tmp.s +endif diff -ur --new-file old/linux/arch/arm/mm/extable.c new/linux/arch/arm/mm/extable.c --- old/linux/arch/arm/mm/extable.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/extable.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,55 @@ +/* + * linux/arch/arm/mm/extable.c + */ + +#include +#include +#include + +extern const struct exception_table_entry __start___ex_table[]; +extern const struct exception_table_entry __stop___ex_table[]; + +static inline unsigned long +search_one_table(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff == 0) + return mid->fixup; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return 0; +} + +unsigned long +search_exception_table(unsigned long addr) +{ + unsigned long ret; + +#ifndef CONFIG_MODULES + /* There is only the kernel to search. */ + ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); + if (ret) return ret; +#else + /* The kernel is the last "module" -- no need to treat it special. */ + struct module *mp; + for (mp = module_list; mp != NULL; mp = mp->next) { + if (mp->ex_table_start == NULL) + continue; + ret = search_one_table(mp->ex_table_start, + mp->ex_table_end - 1, addr); + if (ret) return ret; + } +#endif + + return 0; +} 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 Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/fault-armo.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,159 @@ +/* + * linux/arch/arm/mm/fault.c + * + * Copyright (C) 1995 Linus Torvalds + * Modifications for ARM processor (c) 1995, 1996 Russell King + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define FAULT_CODE_FORCECOW 0x80 +#define FAULT_CODE_PREFETCH 0x04 +#define FAULT_CODE_WRITE 0x02 +#define FAULT_CODE_USER 0x01 + +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(regs->ARM_pc)) != 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 + */ +asmlinkage void +do_DataAbort (unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) +{ + handle_dataabort (min_addr, mode, regs); + + if ((min_addr ^ max_addr) >> PAGE_SHIFT) + handle_dataabort (max_addr, mode | FAULT_CODE_FORCECOW, regs); +} + +asmlinkage int +do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs) +{ +#if 0 + if (the memc mapping for this page exists - can check now...) { + printk ("Page in, but got abort (undefined instruction?)\n"); + return 0; + } +#endif + handle_dataabort (addr, mode, 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 Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/fault-armv.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,200 @@ +/* + * linux/arch/arm/mm/fault.c + * + * Copyright (C) 1995 Linus Torvalds + * Modifications for ARM processor (c) 1995, 1996 Russell King + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define FAULT_CODE_READ 0x02 +#define FAULT_CODE_USER 0x01 + +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 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; + + 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; + + /* + * 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; + } + 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 + 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(regs->ARM_pc)) != 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 + */ +asmlinkage void +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; + + switch (fsr & 15) { + case 2: + DIE(SIGKILL, "Terminal exception") + case 0: + DIE(SIGSEGV, "Vector exception") + case 1: + case 3: + DIE(SIGBUS, "Alignment exception") + case 12: + case 14: + DIE(SIGBUS, "External abort on translation") + case 9: + case 11: + DIE(SIGSEGV, "Domain fault") + case 13:/* permission fault on section */ +#ifndef DEBUG + { + unsigned int i, j, a; +static int count=2; +if (count-- == 0) while (1); + a = regs->ARM_sp; + for (j = 0; j < 10; j++) { + printk ("%08x: ", a); + for (i = 0; i < 8; i += 1, a += 4) + printk ("%08lx ", *(unsigned long *)a); + printk ("\n"); + } + } +#endif + DIE(SIGSEGV, "Permission 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") + case 8: + case 10: + DIE(SIGBUS, "External abort on non-linefetch") + } +} + +asmlinkage int +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); + return 1; +} + 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 Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/init.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,215 @@ +/* + * linux/arch/arm/mm/init.c + * + * Copyright (C) 1995, 1996 Russell King + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_BLK_DEV_INITRD +#include +#endif + +#include +#include +#include +#include +#include +#include + +pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; +extern char _etext, _stext, _edata, __bss_start, _end; +extern char __init_begin, __init_end; + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving a inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +#if PTRS_PER_PTE != 1 +unsigned long *empty_bad_page_table; + +pte_t *__bad_pagetable(void) +{ + int i; + pte_t bad_page; + + 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; +} +#endif + +unsigned long *empty_zero_page; +unsigned long *empty_bad_page; + +pte_t __bad_page(void) +{ + memzero (empty_bad_page, PAGE_SIZE); + return pte_nocache(pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED))); +} + +void show_mem(void) +{ + extern void show_net_buffers(void); + int i,free = 0,total = 0,reserved = 0; + int shared = 0; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + i = MAP_NR(high_memory); + while (i-- > 0) { + total++; + if (PageReserved(mem_map+i)) + reserved++; + else if (!atomic_read(&mem_map[i].count)) + free++; + else + shared += atomic_read(&mem_map[i].count) - 1; + } + printk("%d pages of RAM\n",total); + printk("%d free pages\n",free); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); + show_buffers(); +#ifdef CONFIG_NET + show_net_buffers(); +#endif +} + +/* + * paging_init() sets up the page tables... + */ +unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) +{ + extern unsigned long free_area_init(unsigned long, unsigned long); + + start_mem = PAGE_ALIGN(start_mem); + empty_zero_page = (unsigned long *)start_mem; + start_mem += PAGE_SIZE; + 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 *); +#endif + memzero (empty_zero_page, PAGE_SIZE); + start_mem = setup_pagetables (start_mem, end_mem); + + flush_tlb_all (); + update_mm_cache_all (); + + return free_area_init (start_mem, end_mem); +} + +/* + * mem_init() marks the free areas in the mem_map and tells us how much + * memory is free. This is done after various parts of the system have + * claimed their memory after the kernel image. + */ +void mem_init(unsigned long start_mem, unsigned long end_mem) +{ + extern void sound_init(void); + int codepages = 0; + int reservedpages = 0; + int datapages = 0; + int initpages = 0; + unsigned long tmp; + + end_mem &= PAGE_MASK; + high_memory = (void *)end_mem; + max_mapnr = num_physpages = MAP_NR(end_mem); + + /* mark usable pages in the mem_map[] */ + mark_usable_memory_areas(&start_mem, end_mem); + + 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)) + initpages++; + else if (tmp >= KERNTOPHYS(__bss_start) + && tmp < (unsigned long) start_mem) + datapages++; + else + reservedpages++; + continue; + } + atomic_set(&mem_map[MAP_NR(tmp)].count, 1); +#ifdef CONFIG_BLK_DEV_INITRD + if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end)) +#endif + free_page(tmp); + } + printk ("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n", + (unsigned long) nr_free_pages << (PAGE_SHIFT-10), + max_mapnr << (PAGE_SHIFT-10), + codepages << (PAGE_SHIFT-10), + reservedpages << (PAGE_SHIFT-10), + datapages << (PAGE_SHIFT-10), + initpages << (PAGE_SHIFT-10)); +} + +void free_initmem (void) +{ + unsigned long addr; + + addr = (unsigned long)(&__init_begin); + for (; addr < (unsigned long)(&__init_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); +} + +void si_meminfo(struct sysinfo *val) +{ + int i; + + i = MAP_NR(high_memory); + val->totalram = 0; + val->sharedram = 0; + val->freeram = nr_free_pages << PAGE_SHIFT; + val->bufferram = buffermem; + while (i-- > 0) { + if (PageReserved(mem_map+i)) + continue; + val->totalram++; + if (!atomic_read(&mem_map[i].count)) + continue; + val->sharedram += atomic_read(&mem_map[i].count) - 1; + } + val->totalram <<= PAGE_SHIFT; + val->sharedram <<= PAGE_SHIFT; +} + diff -ur --new-file old/linux/arch/arm/mm/mm-a5k.c new/linux/arch/arm/mm/mm-a5k.c --- old/linux/arch/arm/mm/mm-a5k.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/mm-a5k.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,7 @@ +/* + * arch/arm/mm/mm-a5k.c + * + * Extra MM routines for the Archimedes architecture + * + * Copyright (C) 1998 Russell King + */ 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 Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/mm-arc.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,7 @@ +/* + * arch/arm/mm/mm-arc.c + * + * Extra MM routines for the Archimedes architecture + * + * Copyright (C) 1998 Russell King + */ diff -ur --new-file old/linux/arch/arm/mm/mm-ebsa110.c new/linux/arch/arm/mm/mm-ebsa110.c --- old/linux/arch/arm/mm/mm-ebsa110.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/mm-ebsa110.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,7 @@ +/* + * arch/arm/mm/mm-ebsa110.c + * + * Extra MM routines for the Archimedes architecture + * + * Copyright (C) 1998 Russell King + */ diff -ur --new-file old/linux/arch/arm/mm/mm-nexuspci.c new/linux/arch/arm/mm/mm-nexuspci.c --- old/linux/arch/arm/mm/mm-nexuspci.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/mm-nexuspci.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,7 @@ +/* + * arch/arm/mm/mm-nexuspci.c + * + * Extra MM routines for the Archimedes architecture + * + * Copyright (C) 1998 Russell King + */ diff -ur --new-file old/linux/arch/arm/mm/mm-rpc.c new/linux/arch/arm/mm/mm-rpc.c --- old/linux/arch/arm/mm/mm-rpc.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/mm-rpc.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,80 @@ +/* + * arch/arm/mm/mm-rpc.c + * + * Extra MM routines for RiscPC architecture + * + * Copyright (C) 1998 Russell King + */ + +#include + +#define NR_DRAM_BANKS 4 +#define NR_VRAM_BANKS 1 + +#define NR_BANKS (NR_DRAM_BANKS + NR_VRAM_BANKS) + +#define FIRST_BANK 0 +#define FIRST_DRAM_BANK 0 +#define FIRST_VRAM_BANK NR_DRAM_BANKS + +#define BANK_SHIFT 26 +#define FIRST_DRAM_ADDR 0x10000000 + +#define PHYS_TO_BANK(x) (((x) >> BANK_SHIFT) & (NR_DRAM_BANKS - 1)) +#define BANK_TO_PHYS(x) ((FIRST_DRAM_ADDR) + + (((x) - FIRST_DRAM_BANK) << BANK_SHIFT) + +struct ram_bank { + unsigned int virt_addr; /* virtual address of the *end* of this bank + 1 */ + signed int phys_offset; /* offset to physical address of this bank */ +}; + +static struct ram_bank rambank[NR_BANKS]; + +/* + * Return the physical (0x10000000 -> 0x20000000) address of + * the virtual (0xc0000000 -> 0xd0000000) address + */ +unsigned long __virt_to_phys(unsigned long vpage) +{ + unsigned int bank = FIRST_BANK; + + while (vpage >= rambank[bank].virt_addr && bank < NR_BANKS) + bank ++; + + return vpage - rambank[bank].phys_offset; +} + +/* + * Return the virtual (0xc0000000 -> 0xd0000000) address of + * the physical (0x10000000 -> 0x20000000) address + */ +unsigned long __phys_to_virt(unsigned long phys) +{ + unsigned int bank; + + if (phys > FIRST_DRAM_ADDR) + bank = PHYS_TO_BANK(phys); + else + bank = FIRST_VRAM_BANK; + + return phys + rambank[bank].phys_offset; +} + +void init_dram_banks(struct param_struct *params) +{ + unsigned int bank; + unsigned int bytes = 0; + + for (bank = FIRST_DRAM_BANK; bank < NR_DRAM_BANKS; bank++) { + rambank[bank].phys_offset = PAGE_OFFSET + bytes + - BANK_TO_PHYS(bank); + + bytes += params->u1.s.pages_in_bank[bank - FIRST_DRAM_BANK] * PAGE_SIZE; + + rambank[bank].virt_addr = PAGE_OFFSET + bytes; + } + + drambank[4].phys_offset = 0xd6000000; + drambank[4].virt_addr = 0xd8000000; +} 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 Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/proc-arm2,3.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,494 @@ +/* + * linux/arch/arm/mm/arm2,3.S: MMU functions for ARM2,3 + * + * (C) 1997 Russell King + * + * These are the low level assembler for performing cache + * and memory functions on ARM2, ARM250 and ARM3 processors. + */ +#include + +#include +#include "../lib/constants.h" + +/* + * Code common to all processors - MEMC specific not processor + * specific! + */ + +LC1: .word SYMBOL_NAME(page_nr) +/* + * Function: arm2_3_update_map (struct task_struct *tsk) + * + * Params : tsk Task structure to be updated + * + * Purpose : Re-generate memc maps for task from its pseudo page tables + */ +_arm2_3_update_map: + mov ip, sp + stmfd sp!, {r4 - r6, fp, ip, lr, pc} + sub fp, ip, #4 + add r1, r0, #TSS_MEMCMAP + ldr r2, LC1 + ldr r2, [r2] + mov r3, #0x03f00000 + orr r3, r3, #0x00000f00 + orr r4, r3, #1 + orr r5, r3, #2 + orr r6, r3, #3 +1: stmia r1!, {r3, r4, r5, r6} @ Default mapping (null mapping) + add r3, r3, #4 + add r4, r4, #4 + add r5, r5, #4 + add r6, r6, #4 + stmia r1!, {r3, r4, r5, r6} @ Default mapping (null mapping) + add r3, r3, #4 + add r4, r4, #4 + add r5, r5, #4 + add r6, r6, #4 + subs r2, r2, #8 + bhi 1b + + adr r2, Lphystomemc32 @ r2 = conversion table to logical page number + ldr r4, [r0, #TSS_MEMMAP] @ r4 = active mem map + add r5, r4, #32 << 2 @ r5 = end of active mem map + add r0, r0, #TSS_MEMCMAP @ r0 = memc map + + mov r6, #0 +2: ldmia r4!, {r1, r3} + tst r1, #PAGE_PRESENT + blne update_map_pgd + add r6, r6, #32 << 2 + tst r3, #PAGE_PRESENT + blne update_map_pgd3 + add r6, r6, #32 << 2 + cmp r4, r5 + blt 2b + ldmea fp, {r4 - r6, fp, sp, pc}^ + +@ r0,r2,r3,r4,r5 = preserve +@ r1,ip = available +@ r0 = memc map +@ r1 = pgd entry +@ r2 = conversion table +@ r6 = logical page no << 2 + +update_map_pgd3: + mov r1, r3 +update_map_pgd: stmfd sp!, {r3, r4, r5, lr} + bic r4, r1, #3 @ r4 = page table + sub r5, r6, #1 << 2 + add ip, r4, #32 << 2 @ ip = end of page table + +1: ldr r1, [r4], #4 @ get entry + add r5, r5, #1 << 2 + tst r1, #PAGE_PRESENT @ page present? + blne Lconvertmemc @ yes + ldr r1, [r4], #4 @ get entry + add r5, r5, #1 << 2 + tst r1, #PAGE_PRESENT @ page present? + blne Lconvertmemc @ yes + ldr r1, [r4], #4 @ get entry + add r5, r5, #1 << 2 + tst r1, #PAGE_PRESENT @ page present? + blne Lconvertmemc @ yes + ldr r1, [r4], #4 @ get entry + add r5, r5, #1 << 2 + tst r1, #PAGE_PRESENT @ page present? + blne Lconvertmemc @ yes + cmp r4, ip + blt 1b + ldmfd sp!, {r3, r4, r5, pc}^ + +Lconvertmemc: mov r3, r1, lsr #13 @ + and r3, r3, #0x3fc @ Convert to memc physical page no + ldr r3, [r2, r3] @ + + tst r1, #PAGE_OLD|PAGE_NOT_USER @ check for MEMC read + biceq r3, r3, #0x200 @ + tsteq r1, #PAGE_READONLY|PAGE_CLEAN @ check for MEMC write + biceq r3, r3, #0x300 @ + + orr r3, r3, r5, lsl #13 + and r1, r5, #0x01800000 >> 13 + orr r3, r3, r1 + + and r1, r3, #255 + str r3, [r0, r1, lsl #2] + movs pc, lr + +/* + * Function: arm2_3_update_cache (struct task_struct *tsk, unsigned long addr, pte_t pte) + * Params : tsk Task to update + * address Address of fault. + * pte New PTE at address + * Purpose : Update the mapping for this address. + * Notes : does the ARM3 run faster if you dont use the result in the next instruction? + */ +_arm2_3_update_cache: + tst r2, #PAGE_PRESENT + moveqs pc, lr + mov r3, r2, lsr #13 @ Physical page no. + adr ip, Lphystomemc32 @ Convert to logical page number + and r3, r3, #0x3fc + mov r1, r1, lsr #15 + ldr r3, [ip, r3] @ Convert to memc phys page no. + tst r2, #PAGE_OLD|PAGE_NOT_USER + biceq r3, r3, #0x200 + tsteq r2, #PAGE_READONLY|PAGE_CLEAN + biceq r3, r3, #0x300 + mov ip, sp, lsr #13 + orr r3, r3, r1, lsl #15 + mov ip, ip, lsl #13 + and r1, r1, #0x300 + teq ip, r0 + orr r3, r3, r1, lsl #2 + add r0, r0, #TSS_MEMCMAP + and r2, r3, #255 + streqb r3, [r3] + str r3, [r0, r2, lsl #2] + movs pc, lr + +#define PCD(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af) \ + .long a0| 0x03800300; .long a1| 0x03800300;\ + .long a2| 0x03800300; .long a3| 0x03800300;\ + .long a4| 0x03800300; .long a5| 0x03800300;\ + .long a6| 0x03800300; .long a7| 0x03800300;\ + .long a8| 0x03800300; .long a9| 0x03800300;\ + .long aa| 0x03800300; .long ab| 0x03800300;\ + .long ac| 0x03800300; .long ad| 0x03800300;\ + .long ae| 0x03800300; .long af| 0x03800300 + +@ Table to map from page number to vidc page number +Lphystomemc32: PCD(0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78) + PCD(0x01,0x09,0x11,0x19,0x21,0x29,0x31,0x39,0x41,0x49,0x51,0x59,0x61,0x69,0x71,0x79) + PCD(0x04,0x0C,0x14,0x1C,0x24,0x2C,0x34,0x3C,0x44,0x4C,0x54,0x5C,0x64,0x6C,0x74,0x7C) + PCD(0x05,0x0D,0x15,0x1D,0x25,0x2D,0x35,0x3D,0x45,0x4D,0x55,0x5D,0x65,0x6D,0x75,0x7D) + PCD(0x02,0x0A,0x12,0x1A,0x22,0x2A,0x32,0x3A,0x42,0x4A,0x52,0x5A,0x62,0x6A,0x72,0x7A) + PCD(0x03,0x0B,0x13,0x1B,0x23,0x2B,0x33,0x3B,0x43,0x4B,0x53,0x5B,0x63,0x6B,0x73,0x7B) + PCD(0x06,0x0E,0x16,0x1E,0x26,0x2E,0x36,0x3E,0x46,0x4E,0x56,0x5E,0x66,0x6E,0x76,0x7E) + PCD(0x07,0x0F,0x17,0x1F,0x27,0x2F,0x37,0x3F,0x47,0x4F,0x57,0x5F,0x67,0x6F,0x77,0x7F) + PCD(0x80,0x88,0x90,0x98,0xA0,0xA8,0xB0,0xB8,0xC0,0xC8,0xD0,0xD8,0xE0,0xE8,0xF0,0xF8) + PCD(0x81,0x89,0x91,0x99,0xA1,0xA9,0xB1,0xB9,0xC1,0xC9,0xD1,0xD9,0xE1,0xE9,0xF1,0xF9) + PCD(0x84,0x8C,0x94,0x9C,0xA4,0xAC,0xB4,0xBC,0xC4,0xCC,0xD4,0xDC,0xE4,0xEC,0xF4,0xFC) + PCD(0x85,0x8D,0x95,0x9D,0xA5,0xAD,0xB5,0xBD,0xC5,0xCD,0xD5,0xDD,0xE5,0xED,0xF5,0xFD) + PCD(0x82,0x8A,0x92,0x9A,0xA2,0xAA,0xB2,0xBA,0xC2,0xCA,0xD2,0xDA,0xE2,0xEA,0xF2,0xFA) + PCD(0x83,0x8B,0x93,0x9B,0xA3,0xAB,0xB3,0xBB,0xC3,0xCB,0xD3,0xDB,0xE3,0xEB,0xF3,0xFB) + PCD(0x86,0x8E,0x96,0x9E,0xA6,0xAE,0xB6,0xBE,0xC6,0xCE,0xD6,0xDE,0xE6,0xEE,0xF6,0xFE) + PCD(0x87,0x8F,0x97,0x9F,0xA7,0xAF,0xB7,0xBF,0xC7,0xCF,0xD7,0xDF,0xE7,0xEF,0xF7,0xFF) + +/* + * Function: arm2_3_data_abort () + * + * Params : r0 = address of aborted instruction + * + * Purpose : + * + * Returns : r0 = address of abort + * : r1 = FSR + * : r2 != 0 if writing + */ + +_arm2_3_data_abort: + movs pc, lr + +_arm2_3_check_bugs: + movs pc, lr + +/* + * Processor specific - ARM2 + */ + +LC0: .word SYMBOL_NAME(page_nr) +/* + * Function: arm2_switch_to (struct task_struct *prev, struct task_struct *next) + * + * Params : prev Old task structure + * : next New task structure for process to run + * + * 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. + */ +_arm2_switch_to: + stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack + 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 + ldr r1, LC0 + ldr r1, [r1] +1: ldmia r0!, {r2, r3, r5, r6} + strb r2, [r2] + strb r3, [r3] + strb r5, [r5] + strb r6, [r6] + ldmia r0!, {r2, r3, r5, r6} + strb r2, [r2] + strb r3, [r3] + strb r5, [r5] + strb r6, [r6] + subs r1, r1, #8 + bhi 1b + ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously + +/* + * Function: arm2_remap_memc (struct task_struct *tsk) + * + * Params : tsk Task structure specifing the new mapping structure + * + * Purpose : remap MEMC tables + */ +_arm2_remap_memc: + stmfd sp!, {lr} + add r0, r0, #TSS_MEMCMAP + ldr r1, LC0 + ldr r1, [r1] +1: ldmia r0!, {r2, r3, ip, lr} + strb r2, [r2] + strb r3, [r3] + strb ip, [ip] + strb lr, [lr] + ldmia r0!, {r2, r3, ip, lr} + strb r2, [r2] + strb r3, [r3] + strb ip, [ip] + strb lr, [lr] + subs r1, r1, #8 + bhi 1b + ldmfd sp!, {pc}^ + +/* + * Function: arm2_xchg_1 (int new, volatile void *ptr) + * + * Params : new New value to store at... + * : ptr pointer to byte-wide location + * + * Purpose : Performs an exchange operation + * + * Returns : Original byte data at 'ptr' + * + * Notes : This will have to be changed if we ever use multi-processing using these + * processors, but that is very unlikely... + */ +_arm2_xchg_1: mov r2, pc + orr r2, r2, #I_BIT + teqp r2, #0 + ldrb r2, [r1] + strb r0, [r1] + mov r0, r2 + movs pc, lr + +/* + * Function: arm2_xchg_4 (int new, volatile void *ptr) + * + * Params : new New value to store at... + * : ptr pointer to word-wide location + * + * Purpose : Performs an exchange operation + * + * Returns : Original word data at 'ptr' + * + * Notes : This will have to be changed if we ever use multi-processing using these + * processors, but that is very unlikely... + */ +_arm2_xchg_4: mov r2, pc + orr r2, r2, #I_BIT + teqp r2, #0 + ldr r2, [r1] + str r0, [r1] + mov r0, r2 +/* + * fall through + */ +/* + * Function: arm2_proc_init (void) + * : arm2_proc_fin (void) + * + * Purpose : Initialise / finalise processor specifics (none required) + */ +_arm2_proc_init: +_arm2_proc_fin: movs pc, lr +/* + * Function: arm3_switch_to (struct task_struct *prev, struct task_struct *next) + * + * Params : prev Old task structure + * : next New task structure for process to run + * + * 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. + */ +_arm3_switch_to: + stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack + 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 + ldr r1, LC0 + ldr r1, [r1] +1: ldmia r0!, {r2, r3, r5, r6} + strb r2, [r2] + strb r3, [r3] + strb r5, [r5] + strb r6, [r6] + ldmia r0!, {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 + ldmfd sp!, {r4 - r9, fp, pc}^ @ Load all regs saved previously +/* + * Function: arm3_remap_memc (struct task_struct *tsk) + * + * Params : tsk Task structure specifing the new mapping structure + * + * Purpose : remap MEMC tables + */ +_arm3_remap_memc: + stmfd sp!, {lr} + add r0, r0, #TSS_MEMCMAP + ldr r1, LC0 + ldr r1, [r1] +1: ldmia r0!, {r2, r3, ip, lr} + strb r2, [r2] + strb r3, [r3] + strb ip, [ip] + strb lr, [lr] + ldmia r0!, {r2, r3, ip, lr} + strb r2, [r2] + strb r3, [r3] + strb ip, [ip] + strb lr, [lr] + subs r1, r1, #8 + bhi 1b + mcr p15, 0, r0, c1, c0, 0 @ flush cache + ldmfd sp!, {pc}^ + +/* + * Function: arm3_proc_init (void) + * + * Purpose : Initialise the cache control registers + */ +_arm3_proc_init: + mov r0, #0x001f0000 + orr r0, r0, #0x0000ff00 + orr r0, r0, #0x000000ff + mcr p15, 0, r0, c3, c0 + mcr p15, 0, r0, c4, c0 + mov r0, #0 + mcr p15, 0, r0, c5, c0 + mov r0, #3 + mcr p15, 0, r0, c1, c0 + mcr p15, 0, r0, c2, c0 + movs pc, lr + +/* + * Function: arm3_proc_fin (void) + * + * Purpose : Finalise processor (disable caches) + */ +_arm3_proc_fin: mov r0, #2 + mcr p15, 0, r0, c2, c0 + movs pc, lr + +/* + * Function: arm3_xchg_1 (int new, volatile void *ptr) + * + * Params : new New value to store at... + * : ptr pointer to byte-wide location + * + * Purpose : Performs an exchange operation + * + * Returns : Original byte data at 'ptr' + */ +_arm3_xchg_1: swpb r0, r0, [r1] + movs pc, lr + +/* + * Function: arm3_xchg_4 (int new, volatile void *ptr) + * + * Params : new New value to store at... + * : ptr pointer to word-wide location + * + * Purpose : Performs an exchange operation + * + * Returns : Original word data at 'ptr' + */ +_arm3_xchg_4: swp r0, r0, [r1] + movs pc, lr + + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ +_arm2_name: + .ascii "arm2\0" + .align + + .globl SYMBOL_NAME(arm2_processor_functions) +SYMBOL_NAME(arm2_processor_functions): + .word _arm2_name @ 0 + .word _arm2_switch_to @ 4 + .word _arm2_3_data_abort @ 8 + .word _arm2_3_check_bugs @ 12 + .word _arm2_proc_init @ 16 + .word _arm2_proc_fin @ 20 + + .word _arm2_remap_memc @ 24 + .word _arm2_3_update_map @ 28 + .word _arm2_3_update_cache @ 32 + .word _arm2_xchg_1 @ 36 + .word SYMBOL_NAME(abort) @ 40 + .word _arm2_xchg_4 @ 44 + +_arm250_name: + .ascii "arm250\0" + .align + + .globl SYMBOL_NAME(arm250_processor_functions) +SYMBOL_NAME(arm250_processor_functions): + .word _arm250_name @ 0 + .word _arm2_switch_to @ 4 + .word _arm2_3_data_abort @ 8 + .word _arm2_3_check_bugs @ 12 + .word _arm2_proc_init @ 16 + .word _arm2_proc_fin @ 20 + + .word _arm2_remap_memc @ 24 + .word _arm2_3_update_map @ 28 + .word _arm2_3_update_cache @ 32 + .word _arm3_xchg_1 @ 36 + .word SYMBOL_NAME(abort) @ 40 + .word _arm3_xchg_4 @ 44 + +_arm3_name: + .ascii "arm3\0" + .align + + .globl SYMBOL_NAME(arm3_processor_functions) +SYMBOL_NAME(arm3_processor_functions): + .word _arm3_name @ 0 + .word _arm3_switch_to @ 4 + .word _arm2_3_data_abort @ 8 + .word _arm2_3_check_bugs @ 12 + .word _arm3_proc_init @ 16 + .word _arm3_proc_fin @ 20 + + .word _arm3_remap_memc @ 24 + .word _arm2_3_update_map @ 28 + .word _arm2_3_update_cache @ 32 + .word _arm3_xchg_1 @ 36 + .word SYMBOL_NAME(abort) @ 40 + .word _arm3_xchg_4 @ 44 + 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 Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/proc-arm6,7.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,436 @@ +/* + * linux/arch/arm/mm/arm6.S: MMU functions for ARM6 + * + * (C) 1997 Russell King + * + * These are the low level assembler for performing cache and TLB + * functions on the ARM6 & ARM7. + */ +#include +#include +#include "../lib/constants.h" + +/* + * Function: arm6_7_flush_cache_all (void) + * : arm6_7_flush_cache_page (unsigned long address, int size, int flags) + * + * Params : address Area start address + * : size size of area + * : flags b0 = I cache as well + * + * Purpose : Flush all cache lines + */ +_arm6_7_flush_cache: + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ flush cache +_arm6_7_null: + mov pc, lr + +/* + * Function: arm6_7_flush_tlb_all (void) + * + * Purpose : flush all TLB entries in all caches + */ +_arm6_7_flush_tlb_all: + mov r0, #0 + mcr p15, 0, r0, c5, c0, 0 @ flush TLB + mov pc, lr + +/* + * Function: arm6_7_flush_tlb_page (unsigned long address, int end, int flags) + * + * Params : address Area start address + * : end Area end address + * : flags b0 = I cache as well + * + * Purpose : flush a TLB entry + */ +_arm6_7_flush_tlb_area: +1: mcr p15, 0, r0, c6, c0, 0 @ flush TLB + add r0, r0, #4096 + cmp r0, r1 + 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 + * + * 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. + */ +_arm6_7_switch_to: + stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack + mrs ip, cpsr + 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, #ADDR_LIMIT] + teq r0, #0 + moveq r0, #KERNEL_DOMAIN + movne r0, #USER_DOMAIN + mcr p15, 0, r0, c3, c0 @ Set domain reg + ldr r0, [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, r1, c5, c0, 0 @ flush TLBs + 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: arm6_7_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 + * : sp = pointer to registers + */ + +Lukabttxt: .ascii "Unknown data abort code %d [pc=%p, *pc=%p] LR=%p\0" + .align + +msg: .ascii "DA*%p=%p\n\0" + .align + +_arm6_data_abort: + ldr r4, [r0] @ read instruction causing problem + mov r2, r4, lsr #19 @ r2 b1 = L + and r1, r4, #15 << 24 + add pc, pc, r1, lsr #22 @ Now branch to the relevent processing routine + movs pc, lr + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_earlyldrpost @ ldr rd, [rn], #m + b Ldata_simple @ ldr rd, [rn, #m] @ RegVal + b Ldata_earlyldrpost @ ldr rd, [rn], rm + b Ldata_simple @ ldr rd, [rn, rm] + b Ldata_ldmstm @ ldm*a rn, + b Ldata_ldmstm @ ldm*b rn, + b Ldata_unknown + b Ldata_unknown + b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m + b Ldata_simple @ ldc rd, [rn, #m] + b Ldata_unknown +Ldata_unknown: @ Part of jumptable + ldr r3, [sp, #15 * 4] @ Get PC + str r3, [sp, #-4]! + mov r1, r1, lsr #2 + mov r3, r4 + mov r2, r0 + adr r0, Lukabttxt + bl SYMBOL_NAME(panic) +Lstop: b Lstop + +_arm7_data_abort: + ldr r4, [r0] @ read instruction causing problem + mov r2, r4, lsr #19 @ r2 b1 = L + and r1, r4, #15 << 24 + add pc, pc, r1, lsr #22 @ Now branch to the relevent processing routine + movs pc, lr + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_lateldrpostconst @ ldr rd, [rn], #m + b Ldata_lateldrpreconst @ ldr rd, [rn, #m] @ RegVal + b Ldata_lateldrpostreg @ ldr rd, [rn], rm + b Ldata_lateldrprereg @ ldr rd, [rn, rm] + b Ldata_ldmstm @ ldm*a rn, + b Ldata_ldmstm @ ldm*b rn, + b Ldata_unknown + b Ldata_unknown + b Ldata_simple @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m + b Ldata_simple @ ldc rd, [rn, #m] + b Ldata_unknown + b Ldata_unknown + +Ldata_ldmstm: tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple + + mov r7, #0x11 + orr r7, r7, r7, lsl #8 + and r0, r4, r7 + and r1, r4, r7, lsl #1 + add r0, r0, r1, lsr #1 + and r1, r4, r7, lsl #2 + add r0, r0, r1, lsr #2 + and r1, r4, r7, lsl #3 + add r0, r0, r1, lsr #3 + add r0, r0, r0, lsr #8 + add r0, r0, r0, lsr #4 + and r7, r0, #15 @ r7 = no. of registers to transfer. + and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] @ Get register + eor r6, r4, r4, lsl #2 + tst r6, #1 << 23 @ Check inc/dec ^ writeback + rsbeq r7, r7, #0 + add r7, r0, r7, lsl #2 @ Do correction (signed) + str r7, [sp, r5, lsr #14] @ Put register + +Ldata_simple: and r2, r2, #2 @ check read/write bit + mrc p15, 0, r0, c6, c0, 0 @ get FAR + mrc p15, 0, r1, c5, c0, 0 @ get FSR + and r1, r1, #15 + mov pc, lr + +Ldata_earlyldrpost: + tst r2, #4 + and r2, r2, #2 @ check read/write bit + orrne r2, r2, #1 @ T bit + mrc p15, 0, r0, c6, c0, 0 @ get FAR + mrc p15, 0, r1, c5, c0, 0 @ get FSR + and r1, r1, #15 + mov pc, lr + +Ldata_lateldrpostconst: + movs r1, r4, lsl #20 @ Get offset + beq Ldata_earlyldrpost @ if offset is zero, no effect + and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] + tst r4, #1 << 23 @ U bit + subne r0, r0, r1, lsr #20 + addeq r0, r0, r1, lsr #20 + str r0, [sp, r5, lsr #14] @ Put register + b Ldata_earlyldrpost + +Ldata_lateldrpreconst: + tst r4, #1 << 21 @ check writeback bit + movnes r1, r4, lsl #20 @ Get offset + beq Ldata_simple + and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] + tst r4, #1 << 23 @ U bit + subne r0, r0, r1, lsr #20 + addeq r0, r0, r1, lsr #20 + str r0, [sp, r5, lsr #14] @ Put register + b Ldata_simple + +Ldata_lateldrpostreg: + and r5, r4, #15 + ldr r1, [sp, r5, lsl #2] @ Get Rm + mov r3, r4, lsr #7 + ands r3, r3, #31 + and r6, r4, #0x70 + orreq r6, r6, #8 + add pc, pc, r6 + mov r0, r0 + + mov r1, r1, lsl r3 @ 0: LSL #!0 + b 1f + b 1f @ 1: LSL #0 + mov r0, r0 + b 1f @ 2: MUL? + mov r0, r0 + b 1f @ 3: MUL? + mov r0, r0 + mov r1, r1, lsr r3 @ 4: LSR #!0 + b 1f + mov r1, r1, lsr #32 @ 5: LSR #32 + b 1f + b 1f @ 6: MUL? + mov r0, r0 + b 1f @ 7: MUL? + mov r0, r0 + mov r1, r1, asr r3 @ 8: ASR #!0 + b 1f + mov r1, r1, asr #32 @ 9: ASR #32 + b 1f + b 1f @ A: MUL? + mov r0, r0 + b 1f @ B: MUL? + mov r0, r0 + mov r1, r1, ror r3 @ C: ROR #!0 + b 1f + mov r1, r1, rrx @ D: RRX + b 1f + mov r0, r0 @ E: MUL? + mov r0, r0 + mov r0, r0 @ F: MUL? + + +1: and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] + tst r4, #1 << 23 @ U bit + subne r0, r0, r1 + addeq r0, r0, r1 + str r0, [sp, r5, lsr #14] @ Put register + b Ldata_earlyldrpost + +Ldata_lateldrprereg: + tst r4, #1 << 21 @ check writeback bit + beq Ldata_simple + and r5, r4, #15 + ldr r1, [sp, r5, lsl #2] @ Get Rm + mov r3, r4, lsr #7 + ands r3, r3, #31 + and r6, r4, #0x70 + orreq r6, r6, #8 + add pc, pc, r6 + mov r0, r0 + + mov r1, r1, lsl r3 @ 0: LSL #!0 + b 1f + b 1f @ 1: LSL #0 + mov r0, r0 + b 1f @ 2: MUL? + mov r0, r0 + b 1f @ 3: MUL? + mov r0, r0 + mov r1, r1, lsr r3 @ 4: LSR #!0 + b 1f + mov r1, r1, lsr #32 @ 5: LSR #32 + b 1f + b 1f @ 6: MUL? + mov r0, r0 + b 1f @ 7: MUL? + mov r0, r0 + mov r1, r1, asr r3 @ 8: ASR #!0 + b 1f + mov r1, r1, asr #32 @ 9: ASR #32 + b 1f + b 1f @ A: MUL? + mov r0, r0 + b 1f @ B: MUL? + mov r0, r0 + mov r1, r1, ror r3 @ C: ROR #!0 + b 1f + mov r1, r1, rrx @ D: RRX + b 1f + mov r0, r0 @ E: MUL? + mov r0, r0 + mov r0, r0 @ F: MUL? + + +1: and r5, r4, #15 << 16 @ Get Rn + ldr r0, [sp, r5, lsr #14] + tst r4, #1 << 23 @ U bit + subne r0, r0, r1 + addeq r0, r0, r1 + str r0, [sp, r5, lsr #14] @ Put register + b Ldata_simple + +/* + * Function: arm6_7_check_bugs (void) + * : arm6_7_proc_init (void) + * : arm6_7_proc_fin (void) + * + * Notes : This processor does not require these + */ +_arm6_7_check_bugs: + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip +_arm6_7_proc_init: +_arm6_7_proc_fin: + mov pc, lr + +/* + * Function: arm6_set_pmd () + * + * Params : r0 = Address to set + * : r1 = value to set + * + * Purpose : Set a PMD and flush it out of any WB cache + */ +_arm6_set_pmd: and r2, r1, #3 + teq r2, #2 + andeq r2, r1, #8 + orreq r1, r1, r2, lsl #1 @ Updatable = Cachable + teq r2, #1 + orreq r1, r1, #16 @ Updatable = 1 if Page table + str r1, [r0] + mov pc, lr + +/* + * Function: arm7_set_pmd () + * + * Params : r0 = Address to set + * : r1 = value to set + * + * Purpose : Set a PMD and flush it out of any WB cache + */ +_arm7_set_pmd: orr r1, r1, #16 @ Updatable bit is always set on ARM7 + str r1, [r0] + mov pc, lr + +/* + * Function: _arm6_7_reset + * + * Notes : This sets up everything for a reset + */ +_arm6_7_reset: mrs r1, cpsr + orr r1, r1, #F_BIT|I_BIT + msr cpsr, r1 + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ flush cache + mcr p15, 0, r0, c5, c0, 0 @ flush TLB + mov r1, #F_BIT | I_BIT | 3 + mov pc, lr + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ +_arm6_name: .ascii "arm6\0" + .align + +ENTRY(arm6_processor_functions) + .word _arm6_name @ 0 + .word _arm6_7_switch_to @ 4 + .word _arm6_data_abort @ 8 + .word _arm6_7_check_bugs @ 12 + .word _arm6_7_proc_init @ 16 + .word _arm6_7_proc_fin @ 20 + + .word _arm6_7_flush_cache @ 24 + .word _arm6_7_flush_cache @ 28 + .word _arm6_7_flush_cache @ 32 + .word _arm6_7_null @ 36 + .word _arm6_7_flush_cache @ 40 + .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 + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ +_arm7_name: .ascii "arm7\0" + .align + +ENTRY(arm7_processor_functions) + .word _arm7_name @ 0 + .word _arm6_7_switch_to @ 4 + .word _arm7_data_abort @ 8 + .word _arm6_7_check_bugs @ 12 + .word _arm6_7_proc_init @ 16 + .word _arm6_7_proc_fin @ 20 + + .word _arm6_7_flush_cache @ 24 + .word _arm6_7_flush_cache @ 28 + .word _arm6_7_flush_cache @ 32 + .word _arm6_7_null @ 36 + .word _arm6_7_flush_cache @ 40 + .word _arm6_7_flush_tlb_all @ 44 + .word _arm6_7_flush_tlb_area @ 48 + .word _arm7_set_pmd @ 52 + .word _arm6_7_reset @ 54 + .word _arm6_7_flush_cache @ 58 + 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 Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/proc-sa110.S Wed Jan 21 01:39:42 1998 @@ -0,0 +1,305 @@ +/* + * linux/arch/arm/mm/sa110.S: MMU functions for SA110 + * + * (C) 1997 Russell King + * + * These are the low level assembler for performing cache and TLB + * functions on the sa110. + */ +#include +#include +#include "../lib/constants.h" + + .data +Lclean_switch: .long 0 + .text + +/* + * Function: sa110_flush_cache_all (void) + * + * Purpose : Flush all cache lines + */ + .align 5 +_sa110_flush_cache_all: @ preserves r0 + ldr r3, =Lclean_switch + ldr r2, [r3] + ands r2, r2, #1 + eor r2, r2, #1 + str r2, [r3] + ldr ip, =0xdf000000 + addne ip, ip, #32768 + add r1, ip, #16384 @ only necessary for 16k +1: ldr r2, [ip], #32 + teq r1, ip + bne 1b + mov ip, #0 + mcr p15, 0, ip, c7, c5, 0 @ flush I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * 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 +_sa110_flush_cache_area: + sub r3, r1, r0 + cmp r3, #32768 + bgt _sa110_flush_cache_all +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c6, 1 @ flush D entry + add r0, r0, #32 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c6, 1 @ flush D entry + add r0, r0, #32 + cmp r0, r1 + blt 1b + tst r2, #1 + movne r0, #0 + mcrne p15, 0, r0, c7, c5, 0 @ flush I cache + mov pc, lr + +/* + * Function: sa110_flush_cache_entry (unsigned long address) + * + * Params : address Address of cache line to flush + * + * Purpose : clean & flush an entry + */ + .align 5 +_sa110_flush_cache_entry: + mov r1, #0 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mcr p15, 0, r1, c7, c5, 0 @ flush I cache + mov pc, lr + +/* + * Function: sa110_flush_cache_pte (unsigned long address) + * + * 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) + 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 +_sa110_flush_ram_page: + mov r1, #4096 +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c6, 1 @ flush D entry + add r0, r0, #32 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c6, 1 @ flush D entry + add r0, r0, #32 + subs r1, r1, #64 + bne 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_flush_tlb_all (void) + * + * Purpose : flush all TLB entries in all caches + */ + .align 5 +_sa110_flush_tlb_all: + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ flush I & D tlbs + mov pc, lr + +/* + * Function: sa110_flush_tlb_area (unsigned long address, int 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 +_sa110_flush_tlb_area: + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB +1: cmp r0, r1 + mcrlt p15, 0, r0, c8, c6, 1 @ flush D TLB entry + addlt r0, r0, #4096 + cmp r0, r1 + mcrlt p15, 0, r0, c8, c6, 1 @ flush D TLB entry + addlt r0, r0, #4096 + blt 1b + tst r2, #1 + mcrne p15, 0, r3, c8, c5, 0 @ flush I TLB + mov pc, lr + + .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 + mcr p15, 0, r0, c7, c5, 0 @ flush I cache + mov pc, lr + +@LC0: .word _current +/* + * 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 + * + * 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. + */ + .align 5 +_sa110_switch_to: + stmfd sp!, {r4 - r9, fp, lr} @ Store most regs on stack + mrs ip, cpsr + 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, #ADDR_LIMIT] + teq r0, #0 + moveq r0, #KERNEL_DOMAIN + movne r0, #USER_DOMAIN + mcr p15, 0, r0, c3, c0 @ Set segment + ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer + ldr r3, =Lclean_switch + ldr r2, [r3] + ands r2, r2, #1 + eor r2, r2, #1 + str r2, [r3] + ldr r2, =0xdf000000 + addne r2, r2, #32768 + add r1, r2, #16384 @ only necessary for 16k +1: ldr r3, [r2], #32 + teq r1, r2 + bne 1b + 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, r1, c8, c7, 0 @ flush TLBs + 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 + */ + .align 5 +_sa110_data_abort: + ldr r2, [r0] @ read instruction causing problem + mrc p15, 0, r0, c6, c0, 0 @ get FAR + mov r2, r2, lsr #19 @ b1 = L + and r3, r2, #0x69 << 2 + and r2, r2, #2 +// teq r3, #0x21 << 2 +// orreq r2, r2, #1 @ b0 = {LD,ST}RT + mrc p15, 0, r1, c5, c0, 0 @ get FSR + and r1, r1, #255 + mov pc, lr + +/* + * Function: sa110_set_pmd () + * + * Params : r0 = Address to set + * : r1 = value to set + * + * Purpose : Set a PMD and flush it out of any WB cache + */ + .align 5 +_sa110_set_pmd: str r1, [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 + orr r1, r1, #F_BIT | I_BIT + msr cpsr, r1 + stmfd sp!, {r1, lr} + bl _sa110_flush_cache_all + bl _sa110_flush_tlb_all + mcr p15, 0, ip, c7, c7, 0 @ flush I,D caches + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1800 + bic r0, r0, #0x000f + ldmfd sp!, {r1, pc} +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ +_sa110_name: .ascii "sa110\0" + .align + +ENTRY(sa110_processor_functions) + .word _sa110_name @ 0 + .word _sa110_switch_to @ 4 + .word _sa110_data_abort @ 8 + .word _sa110_check_bugs @ 12 + .word _sa110_proc_init @ 16 + .word _sa110_proc_fin @ 20 + + .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_flush_ram_page @ 40 + .word _sa110_flush_tlb_all @ 44 + .word _sa110_flush_tlb_area @ 48 + + .word _sa110_set_pmd @ 52 + .word _sa110_reset @ 54 + .word _sa110_flush_icache_area @ 58 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 Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/mm/small_page.c Wed Jan 21 01:39:42 1998 @@ -0,0 +1,201 @@ +/* + * linux/arch/arm/mm/small_page.c + * + * Copyright (C) 1996 Russell King + * + * Changelog: + * 26/01/1996 RMK Cleaned up various areas to make little more generic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SMALL_ALLOC_SHIFT (10) +#define SMALL_ALLOC_SIZE (1 << SMALL_ALLOC_SHIFT) +#define NR_BLOCKS (PAGE_SIZE / SMALL_ALLOC_SIZE) + +#if NR_BLOCKS != 4 +#error I only support 4 blocks per page! +#endif + +#define USED(pg) ((atomic_read(&(pg)->count) >> 8) & 15) +#define SET_USED(pg,off) (atomic_read(&(pg)->count) |= 256 << off) +#define CLEAR_USED(pg,off) (atomic_read(&(pg)->count) &= ~(256 << off)) +#define IS_FREE(pg,off) (!(atomic_read(&(pg)->count) & (256 << off))) +#define PAGE_PTR(page,block) ((struct free_small_page *)((page) + \ + ((block) << SMALL_ALLOC_SHIFT))) + +struct free_small_page { + unsigned long next; + unsigned long prev; +}; + +/* + * To handle allocating small pages, we use the main get_free_page routine, + * and split the page up into 4. The page is marked in mem_map as reserved, + * so it can't be free'd by free_page. The count field is used to keep track + * of which sections of this page are allocated. + */ +static unsigned long small_page_ptr; + +static unsigned char offsets[1<next = fsp->prev = 0; + } +} + +static inline void set_page_links_prev(unsigned long page, unsigned long prev) +{ + struct free_small_page *fsp; + unsigned int mask; + int i; + + if (!page) + return; + + mask = USED(&mem_map[MAP_NR(page)]); + for (i = 0; i < NR_BLOCKS; i++) { + if (mask & (1 << i)) + continue; + fsp = PAGE_PTR(page, i); + fsp->prev = prev; + } +} + +static inline void set_page_links_next(unsigned long page, unsigned long next) +{ + struct free_small_page *fsp; + unsigned int mask; + int i; + + if (!page) + return; + + mask = USED(&mem_map[MAP_NR(page)]); + for (i = 0; i < NR_BLOCKS; i++) { + if (mask & (1 << i)) + continue; + fsp = PAGE_PTR(page, i); + fsp->next = next; + } +} + +unsigned long get_small_page(int priority) +{ + struct free_small_page *fsp; + unsigned long new_page; + unsigned long flags; + struct page *page; + int offset; + + save_flags(flags); + if (!small_page_ptr) + goto need_new_page; + cli(); +again: + 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) { + fsp = (struct free_small_page *)new_page; + set_page_links_prev (fsp->next, 0); + small_page_ptr = fsp->next; + } + restore_flags(flags); + return new_page; + +need_new_page: + new_page = __get_free_page(priority); + if (!small_page_ptr) { + if (new_page) { + set_bit (PG_reserved, &mem_map[MAP_NR(new_page)].flags); + clear_page_links (new_page); + cli(); + small_page_ptr = new_page; + goto again; + } + restore_flags(flags); + return 0; + } + free_page(new_page); + cli(); + goto again; +} + +void free_small_page(unsigned long spage) +{ + struct free_small_page *ofsp, *cfsp; + unsigned long flags; + struct page *page; + int offset, oldoffset; + + 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; + } + save_flags_cli (flags); + oldoffset = offsets[USED(page)]; + CLEAR_USED(page, offset); + ofsp = PAGE_PTR(spage, oldoffset); + cfsp = PAGE_PTR(spage, offset); + + if (oldoffset == NR_BLOCKS) { /* going from totally used to mostly used */ + cfsp->prev = 0; + cfsp->next = small_page_ptr; + set_page_links_prev (small_page_ptr, spage); + small_page_ptr = spage; + } else if (!USED(page)) { + set_page_links_prev (ofsp->next, ofsp->prev); + set_page_links_next (ofsp->prev, ofsp->next); + if (spage == small_page_ptr) + small_page_ptr = ofsp->next; + clear_bit (PG_reserved, &page->flags); + restore_flags(flags); + free_page (spage); + } else + *cfsp = *ofsp; + restore_flags(flags); +} diff -ur --new-file old/linux/arch/arm/vmlinux.lds new/linux/arch/arm/vmlinux.lds --- old/linux/arch/arm/vmlinux.lds Thu Jan 1 01:00:00 1970 +++ new/linux/arch/arm/vmlinux.lds Wed Jan 21 01:39:42 1998 @@ -0,0 +1,58 @@ +/* ld script to make i386 Linux kernel + * Written by Martin Mares + */ +OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + _text = .; /* Text and read-only data */ + .text : { + *(.text) + *(.fixup) + *(.gnu.warning) + } = 0x9090 + .text.lock : { *(.text.lock) } /* out-of-line lock text */ + .rodata : { *(.rodata) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; /* End of text section */ + + .data : { /* Data */ + *(.data) + CONSTRUCTORS + } + + _edata = .; /* End of data section */ + + . = ALIGN(4096); /* Init code and data */ + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; /* BSS */ + .bss : { + *(.bss) + } + _end = . ; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -ur --new-file old/linux/arch/i386/.kernel_offset.lds new/linux/arch/i386/.kernel_offset.lds --- old/linux/arch/i386/.kernel_offset.lds Thu Jan 1 01:00:00 1970 +++ new/linux/arch/i386/.kernel_offset.lds Wed Mar 18 06:42:20 1998 @@ -0,0 +1 @@ +__kernel_offset__ = (0x1000-1024)*1024*1024; diff -ur --new-file old/linux/arch/i386/Makefile new/linux/arch/i386/Makefile --- old/linux/arch/i386/Makefile Wed Oct 15 03:24:09 1997 +++ new/linux/arch/i386/Makefile Thu Mar 12 00:10:39 1998 @@ -23,7 +23,9 @@ LDFLAGS=-e stext LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinux.lds $(LDFLAGS) -CFLAGS := $(CFLAGS) -pipe -fno-strength-reduce +CFLAGS_PIPE := -pipe +CFLAGS_NSR := -fno-strength-reduce +CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR) ifdef CONFIG_M386 CFLAGS := $(CFLAGS) -m386 -DCPU=386 @@ -56,6 +58,9 @@ DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a endif +memsize: dummy + @echo "__kernel_offset__ = (0x1000-$(CONFIG_MAX_MEMSIZE))*1024*1024;" > arch/i386/.kernel_offset.lds + arch/i386/kernel: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/i386/kernel @@ -64,27 +69,27 @@ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot -zImage: vmlinux +zImage: memsize vmlinux @$(MAKEBOOT) zImage -bzImage: vmlinux +bzImage: memsize vmlinux @$(MAKEBOOT) bzImage compressed: zImage -zlilo: vmlinux +zlilo: memsize vmlinux @$(MAKEBOOT) BOOTIMAGE=zImage zlilo -bzlilo: vmlinux +bzlilo: memsize vmlinux @$(MAKEBOOT) BOOTIMAGE=bzImage zlilo -zdisk: vmlinux +zdisk: memsize vmlinux @$(MAKEBOOT) BOOTIMAGE=zImage zdisk -bzdisk: vmlinux +bzdisk: memsize vmlinux @$(MAKEBOOT) BOOTIMAGE=bzImage zdisk -install: vmlinux +install: memsize vmlinux @$(MAKEBOOT) BOOTIMAGE=bzImage install archclean: diff -ur --new-file old/linux/arch/i386/boot/bootsect.S new/linux/arch/i386/boot/bootsect.S --- old/linux/arch/i386/boot/bootsect.S Wed Apr 16 23:14:59 1997 +++ new/linux/arch/i386/boot/bootsect.S Sat Feb 21 03:28:21 1998 @@ -22,6 +22,7 @@ ! read errors will result in a unbreakable loop. Reboot by hand. It ! loads pretty fast by getting whole tracks at a time whenever possible. +#include /* for CONFIG_ROOT_RDONLY */ #include .text diff -ur --new-file old/linux/arch/i386/boot/compressed/head.S new/linux/arch/i386/boot/compressed/head.S --- old/linux/arch/i386/boot/compressed/head.S Mon Dec 1 19:34:10 1997 +++ new/linux/arch/i386/boot/compressed/head.S Sat Feb 21 03:28:21 1998 @@ -28,7 +28,6 @@ .text #define __ASSEMBLY__ -#include #include #include diff -ur --new-file old/linux/arch/i386/boot/setup.S new/linux/arch/i386/boot/setup.S --- old/linux/arch/i386/boot/setup.S Mon Dec 29 19:23:54 1997 +++ new/linux/arch/i386/boot/setup.S Thu Feb 19 23:58:40 1998 @@ -410,8 +410,8 @@ mov [68],ebx ! BIOS entry point offset mov [72],cx ! BIOS 16 bit code segment mov [74],dx ! BIOS data segment - mov [78],si ! BIOS code segment length - mov [80],di ! BIOS data segment length + mov [78],esi ! BIOS code segment length + mov [82],di ! BIOS data segment length jmp done_apm_bios no_32_apm_bios: diff -ur --new-file old/linux/arch/i386/boot/tools/build.c new/linux/arch/i386/boot/tools/build.c --- old/linux/arch/i386/boot/tools/build.c Fri May 30 06:53:04 1997 +++ new/linux/arch/i386/boot/tools/build.c Sat Feb 21 03:28:21 1998 @@ -33,7 +33,6 @@ #include #include #include -#include #include typedef unsigned char byte; diff -ur --new-file old/linux/arch/i386/boot/video.S new/linux/arch/i386/boot/video.S --- old/linux/arch/i386/boot/video.S Fri May 16 01:48:01 1997 +++ new/linux/arch/i386/boot/video.S Sat Feb 21 03:28:21 1998 @@ -5,6 +5,8 @@ ! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson ! +#include /* for CONFIG_VIDEO_* */ + ! Enable autodetection of SVGA adapters and modes. If you really need this ! feature, drop me a mail as I think of removing it some day... #undef CONFIG_VIDEO_SVGA diff -ur --new-file old/linux/arch/i386/config.in new/linux/arch/i386/config.in --- old/linux/arch/i386/config.in Fri Mar 27 02:41:48 1998 +++ new/linux/arch/i386/config.in Fri Mar 27 02:42:25 1998 @@ -17,6 +17,7 @@ Pentium/K5/5x86/6x86 CONFIG_M586 \ PPro/K6/6x86MX CONFIG_M686" Pentium bool 'Math emulation' CONFIG_MATH_EMULATION +int ' Max physical memory in MB' CONFIG_MAX_MEMSIZE 1024 endmenu mainmenu_option next_comment @@ -24,7 +25,7 @@ bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD + bool 'Kernel module loader' CONFIG_KMOD fi endmenu @@ -39,9 +40,11 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE fi + bool ' Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC fi bool 'MCA support' CONFIG_MCA bool 'System V IPC' CONFIG_SYSVIPC +bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF @@ -55,6 +58,9 @@ tristate 'Parallel port support' CONFIG_PARPORT if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT + if [ "$CONFIG_PARPORT_PC" != "n" ]; then + bool ' Support foreign hardware' CONFIG_PARPORT_OTHER + fi fi endmenu @@ -91,7 +97,7 @@ endmenu fi -source drivers/net/hamradio/Config.in +source net/ax25/Config.in mainmenu_option next_comment comment 'ISDN subsystem' diff -ur --new-file old/linux/arch/i386/defconfig new/linux/arch/i386/defconfig --- old/linux/arch/i386/defconfig Tue Jan 13 00:29:37 1998 +++ new/linux/arch/i386/defconfig Thu Mar 12 01:07:55 1998 @@ -15,13 +15,14 @@ CONFIG_M586=y # CONFIG_M686 is not set # CONFIG_MATH_EMULATION is not set +CONFIG_MAX_MEMSIZE=1024 # # Loadable module support # CONFIG_MODULES=y # CONFIG_MODVERSIONS is not set -# CONFIG_KERNELD is not set +# CONFIG_KMOD is not set # # General setup @@ -30,8 +31,10 @@ CONFIG_PCI=y CONFIG_PCI_BIOS=y CONFIG_PCI_DIRECT=y +CONFIG_PCI_OLD_PROC=y # CONFIG_MCA is not set CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y @@ -84,13 +87,13 @@ # 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 # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set # CONFIG_IP_ACCT is not set -# CONFIG_IP_MASQUERADE is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set @@ -265,8 +268,6 @@ # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set -# CONFIG_VIDEO_BT848 is not set -# CONFIG_VIDEO_PMS is not set # CONFIG_NVRAM is not set # CONFIG_JOYSTICK is not set # CONFIG_MISC_RADIO is not set @@ -284,6 +285,7 @@ # # Kernel hacking # -# CONFIG_PROFILE is not set +CONFIG_PROFILE=y +CONFIG_PROFILE_SHIFT=2 # CONFIG_MAGIC_SYSRQ is not set CONFIG_VGA_CONSOLE=y diff -ur --new-file old/linux/arch/i386/kernel/Makefile new/linux/arch/i386/kernel/Makefile --- old/linux/arch/i386/kernel/Makefile Mon Dec 22 02:27:17 1997 +++ new/linux/arch/i386/kernel/Makefile Tue Jan 20 21:52:09 1998 @@ -30,9 +30,10 @@ O_OBJS += mca.o endif + ifdef SMP -O_OBJS += smp.o trampoline.o +O_OBJS += io_apic.o smp.o trampoline.o head.o: head.S $(TOPDIR)/include/linux/tasks.h $(CC) -D__ASSEMBLY__ -D__SMP__ -traditional -c $*.S -o $*.o 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 Mon Dec 22 02:27:18 1997 +++ new/linux/arch/i386/kernel/bios32.c Wed Feb 4 01:20:18 1998 @@ -78,6 +78,13 @@ #include #include +#include +#include +#include +#include + +#include "irq.h" + /* * Generic PCI access -- indirect calls according to detected HW. */ @@ -133,7 +140,39 @@ int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned char *value) { - return access_pci->read_config_byte(bus, device_fn, where, value); + int res; + + res = access_pci->read_config_byte(bus, device_fn, where, value); + +#ifdef __SMP__ +/* + * IOAPICs can take PCI IRQs directly, lets first check the mptable: + */ + if (where == PCI_INTERRUPT_LINE) { + int irq; + char pin; + + /* + * get the PCI IRQ INT _physical pin_ for this device + */ + access_pci->read_config_byte(bus, device_fn, + PCI_INTERRUPT_PIN, &pin); + /* + * subtle, PCI pins are numbered starting from 1 ... + */ + pin--; + + irq = IO_APIC_get_PCI_irq_vector (bus,PCI_SLOT(device_fn),pin); + if (irq != -1) + *value = (unsigned char) irq; + + printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n", + bus,PCI_SLOT(device_fn), pin, irq); + + } +#endif + + return res; } int pcibios_read_config_word (unsigned char bus, 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 Sat Jan 10 20:57:29 1998 +++ new/linux/arch/i386/kernel/entry.S Mon Feb 9 20:27:08 1998 @@ -366,7 +366,7 @@ .long SYMBOL_NAME(sys_time) .long SYMBOL_NAME(sys_mknod) .long SYMBOL_NAME(sys_chmod) /* 15 */ - .long SYMBOL_NAME(sys_chown) + .long SYMBOL_NAME(sys_lchown) .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ .long SYMBOL_NAME(sys_stat) .long SYMBOL_NAME(sys_lseek) @@ -532,7 +532,8 @@ .long SYMBOL_NAME(sys_rt_sigsuspend) .long SYMBOL_NAME(sys_pread) /* 180 */ .long SYMBOL_NAME(sys_pwrite) + .long SYMBOL_NAME(sys_chown) - .rept NR_syscalls-181 + .rept NR_syscalls-182 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -ur --new-file old/linux/arch/i386/kernel/head.S new/linux/arch/i386/kernel/head.S --- old/linux/arch/i386/kernel/head.S Tue Dec 23 19:45:12 1997 +++ new/linux/arch/i386/kernel/head.S Thu Mar 12 19:33:21 1998 @@ -11,7 +11,9 @@ #include #include #include -#include +#include +#include + #define CL_MAGIC_ADDR 0x90020 #define CL_MAGIC 0xA33F @@ -55,9 +57,9 @@ * be using the global pages. * * NOTE! We have to correct for the fact that we're - * not yet offset 0xC0000000.. + * not yet offset PAGE_OFFSET.. */ -#define cr4_bits mmu_cr4_features-0xC0000000 +#define cr4_bits mmu_cr4_features-__PAGE_OFFSET movl %cr4,%eax # Turn on 4Mb pages orl cr4_bits,%eax movl %eax,%cr4 @@ -369,7 +371,7 @@ * sets up a idt with 256 entries pointing to * ignore_int, interrupt gates. It doesn't actually load * idt - that can be done only after paging has been enabled - * and the kernel moved to 0xC0000000. Interrupts + * and the kernel moved to PAGE_OFFSET. Interrupts * are enabled elsewhere, when we can be relatively * sure everything is ok. */ @@ -423,11 +425,7 @@ * of tasks we can have.. */ #define IDT_ENTRIES 256 -#ifdef CONFIG_APM -#define GDT_ENTRIES (11+2*NR_TASKS) -#else -#define GDT_ENTRIES (8+2*NR_TASKS) -#endif +#define GDT_ENTRIES (12+2*NR_TASKS) .globl SYMBOL_NAME(idt) @@ -449,14 +447,16 @@ /* * This is initialized to create a identity-mapping at 0-4M (for bootup * purposes) and another mapping of the 0-4M area at virtual address - * 0xC0000000. + * PAGE_OFFSET. */ .org 0x1000 ENTRY(swapper_pg_dir) .long 0x00102007 - .fill 767,4,0 + .fill __USER_PGD_PTRS-1,4,0 + /* default: 767 entries */ .long 0x00102007 - .fill 255,4,0 + /* default: 255 entries */ + .fill __KERNEL_PGD_PTRS-1,4,0 /* * The page tables are initialized to only 4MB here - the final page @@ -619,8 +619,8 @@ .fill 256,8,0 # idt is uninitialized /* - * This gdt setup gives the kernel a 1GB address space at virtual - * address 0xC0000000 - space enough for expansion, I hope. + * This gdt setup gives the kernel a CONFIG_MAX_MEMSIZE sized address space at + * virtual address PAGE_OFFSET. * * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of * gdt entries. Ugh. @@ -637,9 +637,17 @@ .quad 0x00cff2000000ffff /* 0x2b user 4GB data at 0x00000000 */ .quad 0x0000000000000000 /* not used */ .quad 0x0000000000000000 /* not used */ + .quad 0x00c0920000000000 /* 0x40 APM set up for bad BIOS's */ + .quad 0x00c09a0000000000 /* 0x48 APM CS code */ + .quad 0x00809a0000000000 /* 0x50 APM CS 16 code (16 bit) */ + .quad 0x00c0920000000000 /* 0x58 APM DS data */ .fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */ -#ifdef CONFIG_APM - .quad 0x00c09a0000000000 /* APM CS code */ - .quad 0x00809a0000000000 /* APM CS 16 code (16 bit) */ - .quad 0x00c0920000000000 /* APM DS data */ -#endif + +/* + * This is to aid debugging, the various locking macros will be putting + * code fragments here. When an oops occurs we'd rather know that it's + * inside the .text.lock section rather than as some offset from whatever + * function happens to be last in the .text segment. + */ +.section .text.lock +ENTRY(stext_lock) 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 Sun Jan 11 03:04:59 1998 +++ new/linux/arch/i386/kernel/i386_ksyms.c Wed Mar 18 06:15:40 1998 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -35,11 +36,11 @@ EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); +EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__up_wakeup); -EXPORT_SYMBOL(__intel_bh_counter); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); /* Delay loops */ @@ -73,6 +74,9 @@ /* Global SMP irq stuff */ EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(synchronize_bh); +EXPORT_SYMBOL(global_bh_count); +EXPORT_SYMBOL(global_bh_lock); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); @@ -94,3 +98,6 @@ EXPORT_SYMBOL(mca_isadapter); #endif +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff -ur --new-file old/linux/arch/i386/kernel/init_task.c new/linux/arch/i386/kernel/init_task.c --- old/linux/arch/i386/kernel/init_task.c Mon Dec 1 19:34:10 1997 +++ new/linux/arch/i386/kernel/init_task.c Mon Mar 16 23:16:56 1998 @@ -6,6 +6,7 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; +static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -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 Thu Jan 1 01:00:00 1970 +++ new/linux/arch/i386/kernel/io_apic.c Thu Mar 12 19:44:00 1998 @@ -0,0 +1,652 @@ +/* + * Intel IO-APIC support for multi-pentium hosts. + * + * (c) 1997 Ingo Molnar, Hajnalka Szabo + * + * Many thanks to Stig Venaas for trying out countless experimental + * patches and reporting/debugging problems patiently! + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "irq.h" + +#define IO_APIC_BASE 0xfec00000 + +/* + * volatile is justified in this case, it might change + * spontaneously, GCC should not cache it + */ +volatile unsigned int * io_apic_reg = NULL; + +/* + * The structure of the IO-APIC: + */ +struct IO_APIC_reg_00 { + __u32 __reserved_2 : 24, + ID : 4, + __reserved_1 : 4; +} __attribute__ ((packed)); + +struct IO_APIC_reg_01 { + __u32 version : 8, + __reserved_2 : 8, + entries : 8, + __reserved_1 : 8; +} __attribute__ ((packed)); + +struct IO_APIC_reg_02 { + __u32 __reserved_2 : 24, + arbitration : 4, + __reserved_1 : 4; +} __attribute__ ((packed)); + +struct IO_APIC_route_entry { + __u32 vector : 8, + delivery_mode : 3, /* 000: FIXED + * 001: lowest prio + * 111: ExtInt + */ + dest_mode : 1, /* 0: physical, 1: logical */ + delivery_status : 1, + polarity : 1, + irr : 1, + trigger : 1, /* 0: edge, 1: level */ + mask : 1, /* 0: enabled, 1: disabled */ + __reserved_2 : 15; + + union { struct { __u32 + __reserved_1 : 24, + physical_dest : 4, + __reserved_2 : 4; + } physical; + + struct { __u32 + __reserved_1 : 24, + logical_dest : 8; + } logical; + } dest; + +} __attribute__ ((packed)); + +#define UNEXPECTED_IO_APIC() \ + { \ + printk(" WARNING: unexpected IO-APIC, please mail\n"); \ + printk(" to linux-smp@vger.rutgers.edu\n"); \ + } + +int nr_ioapic_registers = 0; /* # of IRQ routing registers */ +int mp_irq_entries = 0; /* # of MP IRQ source entries */ +struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; + /* MP IRQ source entries */ + +unsigned int io_apic_read (unsigned int reg) +{ + *io_apic_reg = reg; + return *(io_apic_reg+4); +} + +void io_apic_write (unsigned int reg, unsigned int value) +{ + *io_apic_reg = reg; + *(io_apic_reg+4) = value; +} + +void enable_IO_APIC_irq (unsigned int irq) +{ + struct IO_APIC_route_entry entry; + + /* + * Enable it in the IO-APIC irq-routing table: + */ + *(((int *)&entry)+0) = io_apic_read(0x10+irq*2); + entry.mask = 0; + io_apic_write(0x10+2*irq, *(((int *)&entry)+0)); +} + +/* + * this function is just here to make things complete, otherwise it's + * unused + */ +void disable_IO_APIC_irq (unsigned int irq) +{ + struct IO_APIC_route_entry entry; + + /* + * Disable it in the IO-APIC irq-routing table: + */ + *(((int *)&entry)+0) = io_apic_read(0x10+irq*2); + entry.mask = 1; + io_apic_write(0x10+2*irq, *(((int *)&entry)+0)); +} + +void clear_IO_APIC_irq (unsigned int irq) +{ + struct IO_APIC_route_entry entry; + + /* + * Disable it in the IO-APIC irq-routing table: + */ + memset(&entry, 0, sizeof(entry)); + entry.mask = 1; + io_apic_write(0x10+2*irq, *(((int *)&entry)+0)); + io_apic_write(0x11+2*irq, *(((int *)&entry)+1)); +} + +/* + * support for broken MP BIOSes, enables hand-redirection of PIRQ0-3 to + * specific CPU-side IRQs. + */ + +#define MAX_PIRQS 8 +int pirq_entries [MAX_PIRQS]; +int pirqs_enabled; + +void ioapic_pirq_setup(char *str, int *ints) +{ + int i, max; + + for (i=0; i IRQ %d\n", i, ints[i+1]); + /* + * PIRQs are mapped upside down, usually. + */ + pirq_entries[MAX_PIRQS-i-1]=ints[i+1]; + } + } +} + +int find_irq_entry(int pin) +{ + int i; + + for (i=0; i=16) && (i<=19)) { + if (pirq_entries[i-16] != -1) { + if (!pirq_entries[i-16]) { + printk("disabling PIRQ%d\n", i-16); + } else { + irq = pirq_entries[i-16]; + printk("using PIRQ%d -> IRQ %d\n", + i-16, irq); + } + } + } + + if (!IO_APIC_IRQ(irq)) + continue; + + entry.vector = IO_APIC_VECTOR(irq); + + /* + * Determine IRQ line polarity (high active or low active): + */ + switch (mp_irqs[idx].mpc_irqflag & 3) + { + case 0: /* conforms, ie. bus-type dependent polarity */ + { + switch (mp_bus_id_to_type[bus]) + { + case MP_BUS_ISA: /* ISA pin */ + { + entry.polarity = 0; + break; + } + case MP_BUS_PCI: /* PCI pin */ + { + entry.polarity = 1; + break; + } + default: + { + printk("broken BIOS!!\n"); + break; + } + } + break; + } + case 1: /* high active */ + { + entry.polarity = 0; + break; + } + case 2: /* reserved */ + { + printk("broken BIOS!!\n"); + break; + } + case 3: /* low active */ + { + entry.polarity = 1; + break; + } + } + + /* + * Determine IRQ trigger mode (edge or level sensitive): + */ + switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) + { + case 0: /* conforms, ie. bus-type dependent */ + { + switch (mp_bus_id_to_type[bus]) + { + case MP_BUS_ISA: /* ISA pin, edge */ + { + entry.trigger = 0; + break; + } + case MP_BUS_PCI: /* PCI pin, level */ + { + entry.trigger = 1; + break; + } + default: + { + printk("broken BIOS!!\n"); + break; + } + } + break; + } + case 1: /* edge */ + { + entry.trigger = 0; + break; + } + case 2: /* reserved */ + { + printk("broken BIOS!!\n"); + break; + } + case 3: /* level */ + { + entry.trigger = 1; + break; + } + } + + io_apic_write(0x10+2*i, *(((int *)&entry)+0)); + io_apic_write(0x11+2*i, *(((int *)&entry)+1)); + } + + if (!first_notcon) + printk(" not connected.\n"); +} + +void setup_IO_APIC_irq_ISA_default (unsigned int irq) +{ + struct IO_APIC_route_entry entry; + + /* + * add it to the IO-APIC irq-routing table: + */ + memset(&entry,0,sizeof(entry)); + + entry.delivery_mode = 1; /* lowest prio */ + entry.dest_mode = 1; /* logical delivery */ + entry.mask = 1; /* unmask IRQ now */ + entry.dest.logical.logical_dest = 0xff; /* all CPUs */ + + entry.vector = IO_APIC_VECTOR(irq); + + entry.polarity=0; + entry.trigger=0; + + io_apic_write(0x10+2*irq, *(((int *)&entry)+0)); + io_apic_write(0x11+2*irq, *(((int *)&entry)+1)); +} + +int IO_APIC_get_PCI_irq_vector (int bus, int slot, int pci_pin) +{ + int i; + + for (i=0; i> 2) & 0x1f)) && + (pci_pin == (mp_irqs[i].mpc_srcbusirq & 3))) + + return mp_irqs[i].mpc_dstirq; + } + return -1; +} + +/* + * There is a nasty bug in some older SMP boards, their mptable lies + * about the timer IRQ. We do the following to work around the situation: + * + * - timer IRQ defaults to IO-APIC IRQ + * - if this function detects that timer IRQs are defunct, then we fall + * back to ISA timer IRQs + */ +static int timer_irq_works (void) +{ + unsigned int t1=jiffies; + unsigned long flags; + + save_flags(flags); + sti(); + + udelay(100*1000); + + if (jiffies-t1>1) + return 1; + + return 0; +} + +void print_IO_APIC (void) +{ + int i; + struct IO_APIC_reg_00 reg_00; + struct IO_APIC_reg_01 reg_01; + struct IO_APIC_reg_02 reg_02; + + *(int *)®_00 = io_apic_read(0); + *(int *)®_01 = io_apic_read(1); + *(int *)®_02 = io_apic_read(2); + + /* + * We are a bit conservative about what we expect, we have to + * know about every HW change ASAP ... + */ + printk("testing the IO APIC.......................\n"); + + printk(".... register #00: %08X\n", *(int *)®_00); + printk("....... : physical APIC id: %02X\n", reg_00.ID); + if (reg_00.__reserved_1 || reg_00.__reserved_2) + UNEXPECTED_IO_APIC(); + + 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 */ + ) + UNEXPECTED_IO_APIC(); + if (reg_01.entries == 0x0f) + printk("....... [IO-APIC cannot route PCI PIRQ 0-3]\n"); + + printk("....... : IO APIC version: %04X\n", reg_01.version); + if ( (reg_01.version != 0x10) && /* oldest IO-APICs */ + (reg_01.version != 0x11) /* my IO-APIC */ + ) + UNEXPECTED_IO_APIC(); + if (reg_01.__reserved_1 || reg_01.__reserved_2) + UNEXPECTED_IO_APIC(); + + printk(".... register #02: %08X\n", *(int *)®_02); + printk("....... : arbitration: %02X\n", reg_02.arbitration); + if (reg_02.__reserved_1 || reg_02.__reserved_2) + UNEXPECTED_IO_APIC(); + + printk(".... IRQ redirection table:\n"); + + printk(" NR Log Phy "); + printk("Mask Trig IRR Pol Stat Dest Deli Vect: \n"); + + for (i=0; i<=reg_01.entries; i++) { + struct IO_APIC_route_entry entry; + + *(((int *)&entry)+0) = io_apic_read(0x10+i*2); + *(((int *)&entry)+1) = io_apic_read(0x11+i*2); + + printk(" %02x %03X %02X ", + i, + entry.dest.logical.logical_dest, + entry.dest.physical.physical_dest + ); + + printk("%1d %1d %1d %1d %1d %1d %1d %02X\n", + entry.mask, + entry.trigger, + entry.irr, + entry.polarity, + entry.delivery_status, + entry.dest_mode, + entry.delivery_mode, + entry.vector + ); + } + + printk(".................................... done.\n"); + + return; +} + +static void init_sym_mode (void) +{ + printk("enabling Symmetric IO mode ... "); + outb (0x70, 0x22); + outb (0x01, 0x23); + printk("...done.\n"); +} + +void init_pic_mode (void) +{ + printk("disabling Symmetric IO mode ... "); + outb (0x70, 0x22); + outb (0x00, 0x23); + printk("...done.\n"); +} + +char ioapic_OEM_ID [16]; +char ioapic_Product_ID [16]; + +struct ioapic_list_entry { + char * oem_id; + char * product_id; +}; + +struct ioapic_list_entry ioapic_whitelist [] = { + + { "INTEL " , "PR440FX " }, + { "INTEL " , "82440FX " }, + { "AIR " , "KDI " }, + { 0 , 0 } +}; + +struct ioapic_list_entry ioapic_blacklist [] = { + + { "OEM00000" , "PROD00000000" }, + { 0 , 0 } +}; + + +static int in_ioapic_list (struct ioapic_list_entry * table) +{ + for (;table->oem_id; table++) + if ((!strcmp(table->oem_id,ioapic_OEM_ID)) && + (!strcmp(table->product_id,ioapic_Product_ID))) + return 1; + return 0; +} + +static int ioapic_whitelisted (void) +{ +/* + * Right now, whitelist everything to see whether the new parsing + * routines really do work for everybody.. + */ +#if 1 + return 1; +#else + return in_ioapic_list(ioapic_whitelist); +#endif +} + +static int ioapic_blacklisted (void) +{ + return in_ioapic_list(ioapic_blacklist); +} + + +void setup_IO_APIC (void) +{ + int i; + /* + * Map the IO APIC into kernel space + */ + + printk("mapping IO APIC from standard address.\n"); + io_apic_reg = ioremap_nocache(IO_APIC_BASE,4096); + printk("new virtual address: %p.\n",io_apic_reg); + + init_sym_mode(); + { + struct IO_APIC_reg_01 reg_01; + + *(int *)®_01 = io_apic_read(1); + nr_ioapic_registers = reg_01.entries+1; + } + + /* + * do not trust the IO-APIC being empty at bootup + */ + for (i=0; i #include #include +#include /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value) @@ -53,12 +54,25 @@ */ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) { + struct thread_struct * t = ¤t->tss; + if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) return -EINVAL; if (!suser()) return -EPERM; + /* + * If it's the first ioperm() call in this thread's lifetime, set the + * IO bitmap up. ioperm() is much less timing critical than clone(), + * this is why we delay this operation until now: + */ +#define IO_BITMAP_OFFSET offsetof(struct thread_struct,io_bitmap) + + if (t->bitmap != IO_BITMAP_OFFSET) { + t->bitmap = IO_BITMAP_OFFSET; + memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4); + } - set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on); + set_bitmap((unsigned long *)t->io_bitmap, from, num, !turn_on); return 0; } 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 Mon Dec 22 02:27:18 1997 +++ new/linux/arch/i386/kernel/irq.c Thu Mar 12 00:09:25 1998 @@ -1,7 +1,7 @@ /* * linux/arch/i386/kernel/irq.c * - * Copyright (C) 1992 Linus Torvalds + * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar * * This file contains the code used by various IRQ handling routines: * asking for different IRQ's should be done through these routines @@ -15,7 +15,6 @@ * Naturally it's not a 1:1 relation, but there are similarities. */ -#include #include #include #include @@ -27,6 +26,7 @@ #include #include #include +#include #include #include @@ -36,150 +36,232 @@ #include #include #include +#include #include "irq.h" -#ifdef __SMP_PROF__ -extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]; -#endif - +unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -#ifdef __SMP__ -atomic_t __intel_bh_counter; -#else -int __intel_bh_counter; -#endif - -#ifdef __SMP_PROF__ -static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},}; -#endif atomic_t nmi_counter; /* - * This contains the irq mask for both irq controllers + * About the IO-APIC, the architecture is 'merged' into our + * current irq architecture, seemlessly. (i hope). It is only + * visible through 8 more hardware interrupt lines, but otherwise + * drivers are unaffected. The main code is believed to be + * NR_IRQS-safe (nothing anymore thinks we have 16 + * irq lines only), but there might be some places left ... + */ + +/* + * This contains the irq mask for both 8259A irq controllers, + * and on SMP the extended IO-APIC IRQs 16-23. The IO-APIC + * uses this mask too, in probe_irq*(). + * + * (0x0000ffff for NR_IRQS==16, 0x00ffffff for NR_IRQS=24) */ -static unsigned int cached_irq_mask = 0xffff; +static unsigned int cached_irq_mask = (1<> 8) & 0xff) spinlock_t irq_controller_lock; +static unsigned int irq_events [NR_IRQS] = { -1, }; +static int disabled_irq [NR_IRQS] = { 0, }; +static int ipi_pending [NR_IRQS] = { 0, }; + /* - * This is always called from an interrupt context - * with local interrupts disabled. Don't worry about - * irq-safe locks. - * - * Note that we always ack the primary irq controller, - * even if the interrupt came from the secondary, as - * the primary will still have routed it. Oh, the joys - * of PC hardware. + * Not all IRQs can be routed through the IO-APIC, eg. on certain (older) + * boards the timer interrupt and sometimes the keyboard interrupt is + * not connected to any IO-APIC pin, it's fed to the CPU ExtInt 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. + */ + +/* + * Default to all normal IRQ's _not_ using the IO APIC. + * + * To get IO-APIC interrupts you should either: + * - turn some of them into IO-APIC interrupts at runtime + * with some magic system call interface. + * - explicitly use irq 16-19 depending on which PCI irq + * line your PCI controller uses. */ -static inline void mask_and_ack_irq(int irq_nr) +unsigned int io_apic_irqs = 0; + +struct hw_interrupt_type { + void (*handle)(unsigned int irq, int cpu, struct pt_regs * regs); + void (*enable)(unsigned int irq); + void (*disable)(unsigned int irq); +}; + + +static void do_8259A_IRQ (unsigned int irq, int cpu, struct pt_regs * regs); +static void enable_8259A_irq (unsigned int irq); +static void disable_8259A_irq (unsigned int irq); + +static struct hw_interrupt_type i8259A_irq_type = { + do_8259A_IRQ, + enable_8259A_irq, + disable_8259A_irq +}; + + +#ifdef __SMP__ +static void do_ioapic_IRQ (unsigned int irq, int cpu, struct pt_regs * regs); +static void enable_ioapic_irq (unsigned int irq); +static void disable_ioapic_irq (unsigned int irq); + +static struct hw_interrupt_type ioapic_irq_type = { + do_ioapic_IRQ, + enable_ioapic_irq, + disable_ioapic_irq +}; +#endif + +struct hw_interrupt_type *irq_handles[NR_IRQS] = { - spin_lock(&irq_controller_lock); - cached_irq_mask |= 1 << irq_nr; - if (irq_nr & 8) { - inb(0xA1); /* DUMMY */ + [0 ... 15] = &i8259A_irq_type /* standard ISA IRQs */ +#ifdef __SMP__ + , [16 ... NR_IRQS-1] = &ioapic_irq_type /* 'high' PCI IRQs */ +#endif +}; + + +/* + * These have to be protected by the irq controller spinlock + * before being called. + */ + +static inline void mask_8259A(unsigned int irq) +{ + cached_irq_mask |= 1 << irq; + if (irq & 8) { outb(cached_A1,0xA1); - outb(0x62,0x20); /* Specific EOI to cascade */ - outb(0x20,0xA0); } else { - inb(0x21); /* DUMMY */ outb(cached_21,0x21); - outb(0x20,0x20); } - spin_unlock(&irq_controller_lock); } -static inline void set_irq_mask(int irq_nr) +static inline void unmask_8259A(unsigned int irq) { - if (irq_nr & 8) { + cached_irq_mask &= ~(1 << irq); + if (irq & 8) { outb(cached_A1,0xA1); } else { outb(cached_21,0x21); } } -/* - * These have to be protected by the spinlock - * before being called. - */ -static inline void mask_irq(unsigned int irq_nr) +void set_8259A_irq_mask(unsigned int irq) { - cached_irq_mask |= 1 << irq_nr; - set_irq_mask(irq_nr); + /* + * (it might happen that we see IRQ>15 on a UP box, with SMP + * emulation) + */ + if (irq < 16) { + if (irq & 8) { + outb(cached_A1,0xA1); + } else { + outb(cached_21,0x21); + } + } } -static inline void unmask_irq(unsigned int irq_nr) +void unmask_generic_irq(unsigned int irq) { - cached_irq_mask &= ~(1 << irq_nr); - set_irq_mask(irq_nr); + if (IO_APIC_IRQ(irq)) + enable_IO_APIC_irq(irq); + else { + cached_irq_mask &= ~(1 << irq); + set_8259A_irq_mask(irq); + } } -void disable_irq(unsigned int irq_nr) -{ - unsigned long flags; +/* + * This builds up the IRQ handler stubs using some ugly macros in irq.h + * + * These macros create the low-level assembly IRQ routines that save + * register context and call do_IRQ(). do_IRQ() then does all the + * operations that are needed to keep the AT (or SMP IOAPIC) + * interrupt-controller happy. + */ - 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; +BUILD_COMMON_IRQ() +/* + * ISA PIC or IO-APIC triggered (INTA-cycle or APIC) interrupts: + */ +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) - spin_lock_irqsave(&irq_controller_lock, flags); - unmask_irq(irq_nr); - spin_unlock_irqrestore(&irq_controller_lock, flags); -} +#ifdef __SMP__ /* - * This builds up the IRQ handler stubs using some ugly macros in irq.h + * The IO-APIC (persent only in SMP boards) has 8 more hardware + * interrupt pins, for all of them we define an IRQ vector: * - * These macros create the low-level assembly IRQ routines that do all - * the operations that are needed to keep the AT interrupt-controller - * happy. They are also written to be fast - and to disable interrupts - * as little as humanly possible. + * raw PCI interrupts 0-3, basically these are the ones used + * heavily: */ +BUILD_IRQ(16) BUILD_IRQ(17) BUILD_IRQ(18) BUILD_IRQ(19) -#if NR_IRQS != 16 -#error make irq stub building NR_IRQS dependent and remove me. -#endif +/* + * [FIXME: anyone with 2 separate PCI buses and 2 IO-APICs, please + * speak up if problems and request experimental patches. + * --mingo ] + */ -BUILD_COMMON_IRQ() -BUILD_IRQ(FIRST,0,0x01) -BUILD_IRQ(FIRST,1,0x02) -BUILD_IRQ(FIRST,2,0x04) -BUILD_IRQ(FIRST,3,0x08) -BUILD_IRQ(FIRST,4,0x10) -BUILD_IRQ(FIRST,5,0x20) -BUILD_IRQ(FIRST,6,0x40) -BUILD_IRQ(FIRST,7,0x80) -BUILD_IRQ(SECOND,8,0x01) -BUILD_IRQ(SECOND,9,0x02) -BUILD_IRQ(SECOND,10,0x04) -BUILD_IRQ(SECOND,11,0x08) -BUILD_IRQ(SECOND,12,0x10) -BUILD_IRQ(SECOND,13,0x20) -BUILD_IRQ(SECOND,14,0x40) -BUILD_IRQ(SECOND,15,0x80) +/* + * MIRQ (motherboard IRQ) interrupts 0-1: + */ +BUILD_IRQ(20) BUILD_IRQ(21) -#ifdef __SMP__ +/* + * 'nondefined general purpose interrupt'. + */ +BUILD_IRQ(22) +/* + * optionally rerouted SMI interrupt: + */ +BUILD_IRQ(23) + +/* + * The following vectors are part of the Linux architecture, there + * is no hardware IRQ pin equivalent for them, they are triggered + * through the ICC by us (IPIs), via smp_message_pass(): + */ BUILD_SMP_INTERRUPT(reschedule_interrupt) BUILD_SMP_INTERRUPT(invalidate_interrupt) BUILD_SMP_INTERRUPT(stop_cpu_interrupt) + +/* + * every pentium local APIC has two 'local interrupts', with a + * soft-definable vector attached to both interrupts, one of + * which is a timer interrupt, the other one is error counter + * overflow. Linux uses the local APIC timer interrupt to get + * a much simpler SMP time architecture: + */ BUILD_SMP_TIMER_INTERRUPT(apic_timer_interrupt) + #endif -static void (*interrupt[17])(void) = { +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 + IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt +#ifdef __SMP__ + ,IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, + IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt +#endif }; /* @@ -215,135 +297,59 @@ */ static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; -static struct irqaction *irq_action[16] = { +static struct irqaction *irq_action[NR_IRQS] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +#ifdef __SMP__ + ,NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL +#endif }; int get_irq_list(char *buf) { - int i; + int i, j; struct irqaction * action; char *p = buf; + p += sprintf(p, " "); + for (j=0; jname); + p += sprintf(p, "%3d: ",i); +#ifndef __SMP__ + p += sprintf(p, "%10u ", kstat_irqs(i)); +#else + for (j=0; jname); + for (action=action->next; action; action = action->next) { p += sprintf(p, ", %s", action->name); } *p++ = '\n'; } p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter)); -#ifdef __SMP_PROF__ +#ifdef __SMP__ p += sprintf(p, "IPI: %10lu\n", ipi_count); #endif return p - buf; } -#ifdef __SMP_PROF__ - -extern unsigned int prof_multiplier[NR_CPUS]; -extern unsigned int prof_counter[NR_CPUS]; - -int get_smp_prof_list(char *buf) { - int i,j, len = 0; - struct irqaction * action; - unsigned long sum_spins = 0; - unsigned long sum_spins_syscall = 0; - unsigned long sum_spins_sys_idle = 0; - unsigned long sum_smp_idle_count = 0; - unsigned long sum_local_timer_ticks = 0; - - for (i=0;ihandler) - continue; - len += sprintf(buf+len, "%3d: %10d ", - i, kstat.interrupts[i]); - for (j=0;jname); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ", %s", action->name); - } - len += sprintf(buf+len, "\n"); - } - len+=sprintf(buf+len, "LCK: %10lu", - sum_spins); - - for (i=0;i (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) { + printk("<[%08lx]> ", x); + } + } +} + + +#define MAXCOUNT 100000000 + +static inline void wait_on_bh(void) { - int local_count = local_irq_count[cpu]; + int count = MAXCOUNT; + do { + if (!--count) { + show("wait_on_bh"); + count = ~0; + } + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 0); +} - /* Are we the only one in an interrupt context? */ - while (local_count != atomic_read(&global_irq_count)) { - /* - * No such luck. Now we need to release the lock, - * _and_ release our interrupt context, because - * otherwise we'd have dead-locks and live-locks - * and other fun things. - */ - atomic_sub(local_count, &global_irq_count); - global_irq_lock = 0; +/* + * I had a lockup scenario where a tight loop doing + * spin_unlock()/spin_lock() on CPU#1 was racing with + * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but + * apparently the spin_unlock() information did not make it + * through to CPU#0 ... nasty, is this by design, do we have to limit + * 'memory update oscillation frequency' artificially like here? + * + * Such 'high frequency update' races can be avoided by careful design, but + * some of our major constructs like spinlocks use similar techniques, + * it would be nice to clarify this issue. Set this define to 0 if you + * want to check wether your system freezes. I suspect the delay done + * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but + * i thought that such things are guaranteed by design, since we use + * the 'LOCK' prefix. + */ +#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 1 + +#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND +# define SYNC_OTHER_CORES(x) udelay(x+1) +#else +/* + * We have to allow irqs to arrive between __sti and __cli + */ +# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") +#endif + +static inline void wait_on_irq(int cpu) +{ + int count = MAXCOUNT; + + for (;;) { /* - * Wait for everybody else to go away and release - * their things before trying to get the lock again. + * 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)) + break; + } + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ + clear_bit(0,&global_irq_lock); + for (;;) { + if (!--count) { + show("wait_on_irq"); + count = ~0; + } + __sti(); + SYNC_OTHER_CORES(cpu); + __cli(); check_smp_invalidate(cpu); if (atomic_read(&global_irq_count)) continue; if (global_irq_lock) continue; + if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + continue; if (!test_and_set_bit(0,&global_irq_lock)) break; } - atomic_add(local_count, &global_irq_count); } } /* * This is called when we want to synchronize with + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +void synchronize_bh(void) +{ + if (atomic_read(&global_bh_count) && !in_interrupt()) + wait_on_bh(); +} + +/* + * This is called when we want to synchronize with * interrupts. We may for example tell a device to * stop sending interrupts: but to make sure there * are no interrupts that are executing on another * CPU we need to call this function. - * - * On UP this is a no-op. */ void synchronize_irq(void) { - int cpu = smp_processor_id(); - int local_count = local_irq_count[cpu]; - - /* Do we need to wait? */ - if (local_count != atomic_read(&global_irq_count)) { - /* The stupid way to do this */ + if (atomic_read(&global_irq_count)) { + /* Stupid approach */ cli(); sti(); } } -static inline void get_irqlock(int cpu, unsigned long where) +static inline void get_irqlock(int cpu) { if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ @@ -441,105 +523,330 @@ } while (test_bit(0,&global_irq_lock)); } while (test_and_set_bit(0,&global_irq_lock)); } - /* - * Ok, we got the lock bit. - * But that's actually just the easy part.. Now - * we need to make sure that nobody else is running + /* + * We also to make sure that nobody else is running * in an interrupt context. */ - wait_on_irq(cpu, where); + wait_on_irq(cpu); /* - * Finally. + * Ok, finally.. */ global_irq_holder = cpu; - previous_irqholder = where; } +/* + * A global "cli()" while in an interrupt context + * turns into just a local cli(). Interrupts + * should use spinlocks for the (very unlikely) + * case that they ever want to protect against + * each other. + */ void __global_cli(void) { int cpu = smp_processor_id(); - unsigned long where; - __asm__("movl 16(%%esp),%0":"=r" (where)); __cli(); - get_irqlock(cpu, where); + if (!local_irq_count[cpu]) + get_irqlock(cpu); } void __global_sti(void) { - release_irqlock(smp_processor_id()); + int cpu = smp_processor_id(); + + if (!local_irq_count[cpu]) + release_irqlock(cpu); __sti(); } unsigned long __global_save_flags(void) { - return global_irq_holder == (unsigned char) smp_processor_id(); + if (!local_irq_count[smp_processor_id()]) + return global_irq_holder == (unsigned char) smp_processor_id(); + else { + unsigned long x; + __save_flags(x); + return x; + } } void __global_restore_flags(unsigned long flags) { - switch (flags) { - case 0: - release_irqlock(smp_processor_id()); - __sti(); - break; - case 1: - __global_cli(); - break; - default: - printk("global_restore_flags: %08lx (%08lx)\n", - flags, (&flags)[-1]); - } + if (!local_irq_count[smp_processor_id()]) { + switch (flags) { + case 0: + __global_sti(); + break; + case 1: + __global_cli(); + break; + default: + printk("global_restore_flags: %08lx (%08lx)\n", + flags, (&flags)[-1]); + } + } else + __restore_flags(flags); } #endif -/* - * do_IRQ handles all normal device IRQ's (the special - * SMP cross-CPU interrupts have their own specific - * handlers). - */ -asmlinkage void do_IRQ(struct pt_regs regs) +static int handle_IRQ_event(unsigned int irq, struct pt_regs * regs) { - int irq = regs.orig_eax & 0xff; struct irqaction * action; - int status, cpu; - - /* - * mask and ack quickly, we don't want the irq controller - * thinking we're snobs just because some other CPU has - * disabled global interrupts (we have already done the - * INT_ACK cycles, it's too late to try to pretend to the - * controller that we aren't taking the interrupt). - */ - mask_and_ack_irq(irq); + int status; - cpu = smp_processor_id(); - irq_enter(cpu, irq); - kstat.interrupts[irq]++; - - /* Return with this interrupt masked if no action */ status = 0; action = *(irq + irq_action); + if (action) { + status |= 1; + if (!(action->flags & SA_INTERRUPT)) __sti(); do { status |= action->flags; - action->handler(irq, action->dev_id, ®s); + action->handler(irq, action->dev_id, regs); action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); __cli(); + } + + return status; +} + + +void disable_irq(unsigned int irq) +{ + unsigned long flags; + + spin_lock_irqsave(&irq_controller_lock, flags); + irq_handles[irq]->disable(irq); + spin_unlock_irqrestore(&irq_controller_lock, flags); + + synchronize_irq(); +} + +/* + * disable/enable_irq() wait for all irq contexts to finish + * executing. Also it's recursive. + */ +static void disable_8259A_irq(unsigned int irq) +{ + disabled_irq[irq]++; + cached_irq_mask |= 1 << irq; + set_8259A_irq_mask(irq); +} + +#ifdef __SMP__ +static void disable_ioapic_irq(unsigned int irq) +{ + disabled_irq[irq]++; + /* + * We do not disable IO-APIC irqs in hardware ... + */ +} +#endif + +void enable_8259A_irq (unsigned int irq) +{ + unsigned long flags; + spin_lock_irqsave(&irq_controller_lock, flags); + if (disabled_irq[irq]) + disabled_irq[irq]--; + else { + spin_unlock_irqrestore(&irq_controller_lock, flags); + return; + } + cached_irq_mask &= ~(1 << irq); + set_8259A_irq_mask(irq); + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +#ifdef __SMP__ +void enable_ioapic_irq (unsigned int irq) +{ + unsigned long flags, should_handle_irq; + int cpu = smp_processor_id(); + + spin_lock_irqsave(&irq_controller_lock, flags); + if (disabled_irq[irq]) + disabled_irq[irq]--; + else { + spin_unlock_irqrestore(&irq_controller_lock, flags); + return; + } +#if 0 + /* + * In the SMP+IOAPIC case it might happen that there are an unspecified + * number of pending IRQ events unhandled. These cases are very rare, + * so we 'resend' these IRQs via IPIs, to the same CPU. It's much + * better to do it this way as thus we dont have to be aware of + * 'pending' interrupts in the IRQ path, except at this point. + */ + if (!disabled_irq[irq] && irq_events[irq]) { + if (!ipi_pending[irq]) { + ipi_pending[irq] = 1; + --irq_events[irq]; + send_IPI(cpu,IO_APIC_VECTOR(irq)); + } + } + spin_unlock_irqrestore(&irq_controller_lock, flags); +#else + if (!disabled_irq[irq] && irq_events[irq]) { + struct pt_regs regs; /* FIXME: these are fake currently */ + + disabled_irq[irq]++; + hardirq_enter(cpu); + spin_unlock(&irq_controller_lock); + + release_irqlock(cpu); + while (test_bit(0,&global_irq_lock)) mb(); +again: + handle_IRQ_event(irq, ®s); + + spin_lock(&irq_controller_lock); + disabled_irq[irq]--; + should_handle_irq=0; + if (--irq_events[irq] && !disabled_irq[irq]) { + should_handle_irq=1; + disabled_irq[irq]++; + } + spin_unlock(&irq_controller_lock); + + if (should_handle_irq) + goto again; + + irq_exit(cpu, irq); + __restore_flags(flags); + } else + spin_unlock_irqrestore(&irq_controller_lock, flags); +#endif +} +#endif + +void enable_irq(unsigned int irq) +{ + irq_handles[irq]->enable(irq); +} + +void make_8259A_irq (unsigned int irq) +{ + io_apic_irqs &= ~(1<handle(irq, cpu, ®s); + /* * This should be conditional: we should really get * a return code from the irq handler to tell us @@ -552,7 +859,7 @@ } } -int setup_x86_irq(int irq, struct irqaction * new) +int setup_x86_irq(unsigned int irq, struct irqaction * new) { int shared = 0; struct irqaction *old, **p; @@ -581,7 +888,18 @@ if (!shared) { spin_lock(&irq_controller_lock); - unmask_irq(irq); +#ifdef __SMP__ + if (IO_APIC_IRQ(irq)) { + irq_handles[irq] = &ioapic_irq_type; + /* + * First disable it in the 8259A: + */ + cached_irq_mask |= 1 << irq; + if (irq < 16) + set_8259A_irq_mask(irq); + } +#endif + unmask_generic_irq(irq); spin_unlock(&irq_controller_lock); } restore_flags(flags); @@ -597,12 +915,13 @@ int retval; struct irqaction * action; - if (irq > 15) + if (irq >= NR_IRQS) return -EINVAL; if (!handler) return -EINVAL; - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + action = (struct irqaction *) + kmalloc(sizeof(struct irqaction), GFP_KERNEL); if (!action) return -ENOMEM; @@ -625,7 +944,7 @@ struct irqaction * action, **p; unsigned long flags; - if (irq > 15) { + if (irq >= NR_IRQS) { printk("Trying to free IRQ%d\n",irq); return; } @@ -644,42 +963,104 @@ printk("Trying to free free IRQ%d\n",irq); } +/* + * probing is always single threaded [FIXME: is this true?] + */ +static unsigned int probe_irqs[NR_CPUS][NR_IRQS]; + unsigned long probe_irq_on (void) { - unsigned int i, irqs = 0; + unsigned int i, j, irqs = 0; unsigned long delay; - /* first, enable any unassigned irqs */ - for (i = 15; i > 0; i--) { + /* + * save current irq counts + */ + memcpy(probe_irqs,kstat.irqs,NR_CPUS*NR_IRQS*sizeof(int)); + + /* + * first, enable any unassigned irqs + */ + for (i = NR_IRQS-1; i > 0; i--) { if (!irq_action[i]) { - enable_irq(i); + unsigned long flags; + spin_lock_irqsave(&irq_controller_lock, flags); + unmask_generic_irq(i); irqs |= (1 << i); + spin_unlock_irqrestore(&irq_controller_lock, flags); } } - /* wait for spurious interrupts to mask themselves out again */ + /* + * wait for spurious interrupts to increase counters + */ for (delay = jiffies + HZ/10; delay > jiffies; ) - /* about 100ms delay */; + /* about 100ms delay */ synchronize_irq(); - /* now filter out any obviously spurious interrupts */ - return irqs & ~cached_irq_mask; + /* + * now filter out any obviously spurious interrupts + */ + for (i=0; i> 8 , 0x40); /* MSB */ - for (i = 0; i < NR_IRQS ; i++) + printk("INIT IRQ\n"); + for (i=0; i + +static inline void irq_enter(int cpu, unsigned int irq) { hardirq_enter(cpu); while (test_bit(0,&global_irq_lock)) { @@ -17,17 +57,25 @@ } } -static inline void irq_exit(int cpu, int irq) +static inline void irq_exit(int cpu, unsigned int irq) { hardirq_exit(cpu); release_irqlock(cpu); } +#define IO_APIC_IRQ(x) ((1<base_addr; - limit = ldt_info->limit; - if (ldt_info->limit_in_pages) - limit = limit * PAGE_SIZE + PAGE_SIZE - 1; - - first = base; - last = limit + base; - - /* segment grows down? */ - if (ldt_info->contents == 1) { - /* data segment grows down */ - first = base+limit+1; - last = base+65535; - if (ldt_info->seg_32bit) - last = base-1; - } - return (last >= first && last < TASK_SIZE); -} - static int write_ldt(void * ptr, unsigned long bytecount, int oldmode) { struct modify_ldt_ldt_s ldt_info; @@ -71,9 +46,6 @@ return -EFAULT; if ((ldt_info.contents == 3 && (oldmode || ldt_info.seg_not_present == 0)) || ldt_info.entry_number >= LDT_ENTRIES) - return -EINVAL; - - if (!limits_ok(&ldt_info) && (oldmode || ldt_info.seg_not_present == 0)) return -EINVAL; if (!current->ldt) { 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 Wed Apr 16 23:14:59 1997 +++ new/linux/arch/i386/kernel/mca.c Sun Jan 25 19:05:46 1998 @@ -65,7 +65,7 @@ static long mca_do_proc_init( long memory_start, long memory_end ); static int mca_default_procfn( char* buf, int slot ); -static long proc_mca_read( struct inode*, struct file*, char* buf, unsigned long count ); +static ssize_t proc_mca_read( struct file*, char*, size_t, loff_t *); static struct file_operations proc_mca_operations = { NULL, proc_mca_read, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL @@ -527,7 +527,7 @@ */ static int mca_fill( char* page, int pid, int type, char** start, - off_t offset, int length) + loff_t *offset, int length) { int len = 0; int slot = 0; @@ -571,8 +571,8 @@ #define PROC_BLOCK_SIZE (3*1024) -long proc_mca_read( struct inode* inode, struct file* file, - char* buf, unsigned long count) +static ssize_t proc_mca_read( struct file* file, + char* buf, size_t count, loff_t *ppos) { unsigned long page; char *start; @@ -580,6 +580,7 @@ int end; unsigned int type, pid; struct proc_dir_entry *dp; + struct inode *inode = file->f_dentry->d_inode; if (count < 0) return -EINVAL; @@ -593,7 +594,7 @@ start = 0; dp = (struct proc_dir_entry *) inode->u.generic_ip; length = mca_fill((char *) page, pid, type, - &start, file->f_pos, count); + &start, ppos, count); if (length < 0) { free_page(page); return length; @@ -601,19 +602,19 @@ if (start != 0) { /* We have had block-adjusting processing! */ copy_to_user(buf, start, length); - file->f_pos += length; + *ppos += length; count = length; } else { /* Static 4kB (or whatever) block capacity */ - if (file->f_pos >= length) { + if (*ppos >= length) { free_page(page); return 0; } - if (count + file->f_pos > length) - count = length - file->f_pos; - end = count + file->f_pos; - copy_to_user(buf, (char *) page + file->f_pos, count); - file->f_pos = end; + if (count + *ppos > length) + count = length - *ppos; + end = count + *ppos; + copy_to_user(buf, (char *) page + *ppos, count); + *ppos = end; } free_page(page); return count; 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 Mon Dec 22 02:27:18 1997 +++ new/linux/arch/i386/kernel/process.c Sun Mar 15 19:25:42 1998 @@ -44,6 +44,7 @@ #ifdef CONFIG_MATH_EMULATION #include #endif +#include "irq.h" #ifdef __SMP__ asmlinkage void ret_from_smpfork(void) __asm__("ret_from_smpfork"); @@ -280,6 +281,12 @@ void machine_restart(char * __unused) { +#if __SMP__ + /* + * turn off the IO-APIC, so we can do a clean reboot + */ + init_pic_mode(); +#endif if(!reboot_thru_bios) { /* rebooting needs to touch the page at absolute addr 0 */ @@ -314,10 +321,10 @@ /* Remap the kernel at virtual address zero, as well as offset zero from the kernel segment. This assumes the kernel segment starts at - virtual address 0xc0000000. */ + virtual address PAGE_OFFSET. */ - memcpy (swapper_pg_dir, swapper_pg_dir + 768, - sizeof (swapper_pg_dir [0]) * 256); + memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, + sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); /* Make sure the first page is mapped to the start of physical memory. It is normally not mapped, to trap kernel NULL pointer dereferences. */ @@ -473,7 +480,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, struct task_struct * p, struct pt_regs * regs) { - int i; struct pt_regs * childregs; p->tss.tr = _TSS(nr); @@ -510,9 +516,13 @@ set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512); else set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1); - p->tss.bitmap = offsetof(struct thread_struct,io_bitmap); - for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */ - p->tss.io_bitmap[i] = ~0; + /* + * a bitmap offset pointing outside of the TSS limit causes a nicely + * controllable SIGSEGV. The first sys_ioperm() call sets up the + * bitmap properly. + */ + p->tss.bitmap = sizeof(struct thread_struct); + if (last_task_used_math == current) __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387)); 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 Wed Dec 24 05:23:53 1997 +++ new/linux/arch/i386/kernel/ptrace.c Thu Mar 12 01:07:20 1998 @@ -2,6 +2,7 @@ /* By Ross Biro 1/23/92 */ /* edited by Linus Torvalds */ +#include /* for CONFIG_MATH_EMULATION */ #include #include #include @@ -370,7 +371,10 @@ if (pid == 1) /* you may not mess with init */ goto out; ret = -ESRCH; - if (!(child = find_task_by_pid(pid))) + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!!! */ + if (!child) goto out; ret = -EPERM; if (request == PTRACE_ATTACH) { @@ -389,9 +393,13 @@ goto out; child->flags |= PF_PTRACED; 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); } send_sig(SIGSTOP, child, 1); ret = 0; @@ -544,6 +552,7 @@ } case PTRACE_DETACH: { /* detach a process that was attached. */ + unsigned long flags; long tmp; ret = -EIO; @@ -552,9 +561,11 @@ child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; + write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); /* make sure the single step bit is not set. */ tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG; put_stack_long(child, EFL_OFFSET, tmp); 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 Tue Dec 23 19:47:27 1997 +++ new/linux/arch/i386/kernel/setup.c Thu Feb 26 00:30:22 1998 @@ -331,16 +331,18 @@ static struct cpu_model_info cpu_models[] __initdata = { { X86_VENDOR_INTEL, 4, - { "486 DX-25/33", "486 DX-50", "486 SX", "487 DX", "486 DX/2", "486 SL", "486 SX/2", - NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL }}, + { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", + "486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, + NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_INTEL, 5, { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75+", "OverDrive PODP5V83", "Pentium MMX", NULL, NULL, "Mobile Pentium 75+", "Mobile Pentium MMX", NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_INTEL, 6, - { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II", NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, + { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", + NULL, "Pentium II (Deschutes)", NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }}, { X86_VENDOR_CYRIX, 4, { NULL, NULL, NULL, NULL, "MediaGX", NULL, NULL, NULL, NULL, "5x86", NULL, NULL, NULL, NULL, NULL, NULL }}, @@ -348,8 +350,8 @@ { NULL, NULL, "6x86", NULL, "GXm", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_CYRIX, 6, - { "6x86MX", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL }}, + { "6x86MX", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_AMD, 4, { NULL, NULL, NULL, "DX/2", NULL, NULL, NULL, "DX/2-WB", "DX/4", "DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT", "Am5x86-WB" }}, @@ -382,8 +384,7 @@ c->cpuid_level < 0) return; - if ((c->x86_vendor == X86_VENDOR_AMD && amd_model(c)) || - (c->x86_vendor == X86_VENDOR_CYRIX && cyrix_model(c))) + if (c->x86_vendor == X86_VENDOR_CYRIX && cyrix_model(c)) return; if (c->x86_model < 16) @@ -393,10 +394,15 @@ p = cpu_models[i].model_names[c->x86_model]; break; } - if (p) + if (p) { strcpy(c->x86_model_id, p); - else - sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model); + return; + } + + if (c->x86_vendor == X86_VENDOR_AMD && amd_model(c)) + return; + + sprintf(c->x86_model_id, "%02x/%02x", c->x86_vendor, c->x86_model); } static char *cpu_vendor_names[] __initdata = { @@ -436,8 +442,8 @@ static const char *x86_cap_flags[] = { "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", "cx8", "apic", "10", "sep", "mtrr", "pge", "mca", "cmov", - "16", "17", "18", "19", "20", "21", "22", "mmx", - "24", "25", "26", "27", "28", "29", "30", "31" + "fcmov", "17", "18", "19", "20", "21", "22", "mmx", + "osfxsr", "25", "26", "27", "28", "29", "30", "amd3d" }; struct cpuinfo_x86 *c = cpu_data; int i, n; diff -ur --new-file old/linux/arch/i386/kernel/signal.c new/linux/arch/i386/kernel/signal.c --- old/linux/arch/i386/kernel/signal.c Tue Dec 30 16:58:00 1997 +++ new/linux/arch/i386/kernel/signal.c Sat Feb 7 01:29:04 1998 @@ -365,21 +365,33 @@ /* non-iBCS2 extensions.. */ __put_user(mask, &sc->oldmask); __put_user(current->tss.cr2, &sc->cr2); -} +} + +/* + * Determine which stack to use.. + */ +static inline unsigned long sigstack_esp(struct k_sigaction *ka, struct pt_regs * regs) +{ + unsigned long esp; + + /* Default to using normal stack */ + esp = regs->esp; + + /* This is the legacy signal stack switching. */ + if ((regs->xss & 0xffff) != __USER_DS && + !(ka->sa.sa_flags & SA_RESTORER) && + ka->sa.sa_restorer) + esp = (unsigned long) ka->sa.sa_restorer; + + return esp; +} static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { struct sigframe *frame; - frame = (struct sigframe *)((regs->esp - sizeof(*frame)) & -8); - - /* XXX: Check here if we need to switch stacks.. */ - - /* This is legacy signal stack switching. */ - if ((regs->xss & 0xffff) != __USER_DS - && !(ka->sa.sa_flags & SA_RESTORER) && ka->sa.sa_restorer) - frame = (struct sigframe *) ka->sa.sa_restorer; + frame = (struct sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -8); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto segv_and_exit; @@ -441,14 +453,7 @@ { struct rt_sigframe *frame; - frame = (struct rt_sigframe *)((regs->esp - sizeof(*frame)) & -8); - - /* XXX: Check here if we need to switch stacks.. */ - - /* This is legacy signal stack switching. */ - if ((regs->xss & 0xffff) != __USER_DS - && !(ka->sa.sa_flags & SA_RESTORER) && ka->sa.sa_restorer) - frame = (struct rt_sigframe *) ka->sa.sa_restorer; + frame = (struct rt_sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -8); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto segv_and_exit; 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 Mon Jan 12 23:47:46 1998 +++ new/linux/arch/i386/kernel/smp.c Thu Mar 12 00:09:25 1998 @@ -52,6 +52,8 @@ #include "irq.h" +spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED; + extern unsigned long start_kernel, _etext; extern void update_one_process( struct task_struct *p, unsigned long ticks, unsigned long user, @@ -115,7 +117,7 @@ int smp_num_cpus = 1; /* Total count of live CPU's */ int smp_threads_ready=0; /* Set when the idlers are all forked */ volatile int cpu_number_map[NR_CPUS]; /* which CPU maps to which logical number */ -volatile int cpu_logical_map[NR_CPUS]; /* which logical number maps to which CPU */ +volatile int __cpu_logical_map[NR_CPUS]; /* which logical number maps to which CPU */ volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */ volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map that's also checked in the spinlock */ volatile unsigned long kstack_ptr; /* Stack vector for booting CPU's */ @@ -139,28 +141,19 @@ volatile unsigned long syscall_count=0; /* Number of times the processor holds the syscall lock */ volatile unsigned long ipi_count; /* Number of IPI's delivered */ -#ifdef __SMP_PROF__ -volatile unsigned long smp_spins[NR_CPUS]={0}; /* Count interrupt spins */ -volatile unsigned long smp_spins_syscall[NR_CPUS]={0}; /* Count syscall spins */ -volatile unsigned long smp_spins_syscall_cur[NR_CPUS]={0};/* Count spins for the actual syscall */ -volatile unsigned long smp_spins_sys_idle[NR_CPUS]={0}; /* Count spins for sys_idle */ -volatile unsigned long smp_idle_count[1+NR_CPUS]={0,}; /* Count idle ticks */ - -/* Count local APIC timer ticks */ -volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]={0,}; - -#endif -#if defined (__SMP_PROF__) -volatile unsigned long smp_idle_map=0; /* Map for idle processors */ -#endif volatile unsigned long smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */ volatile int smp_process_available=0; const char lk_lockmsg[] = "lock from interrupt context at %p\n"; +int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, }; +extern int mp_irq_entries; +extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; +int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, }; +int mp_current_pci_id = 0; -/*#define SMP_DEBUG*/ +/* #define SMP_DEBUG */ #ifdef SMP_DEBUG #define SMP_PRINTK(x) printk x @@ -187,7 +180,7 @@ max_cpus = 0; } -static inline void ack_APIC_irq (void) +void ack_APIC_irq (void) { /* Clear the IPI */ @@ -269,10 +262,14 @@ } memcpy(str,mpc->mpc_oem,8); str[8]=0; + memcpy(ioapic_OEM_ID,str,9); printk("OEM ID: %s ",str); + memcpy(str,mpc->mpc_productid,12); str[12]=0; + memcpy(ioapic_Product_ID,str,13); printk("Product ID: %s ",str); + printk("APIC at: 0x%lX\n",mpc->mpc_lapic); /* set the local APIC address */ @@ -338,6 +335,18 @@ 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)) + mp_bus_id_to_type[m->mpc_busid] = + MP_BUS_ISA; + else + if (strncmp(m->mpc_bustype,"PCI",3) == 0) { + mp_bus_id_to_type[m->mpc_busid] = + MP_BUS_PCI; + mp_bus_id_to_pci_bus[m->mpc_busid] = + mp_current_pci_id; + mp_current_pci_id++; + } mpt+=sizeof(*m); count+=sizeof(*m); break; @@ -363,6 +372,13 @@ struct mpc_config_intsrc *m= (struct mpc_config_intsrc *)mpt; + mp_irqs [mp_irq_entries] = *m; + if (++mp_irq_entries == MAX_IRQ_SOURCES) { + printk("Max irq sources exceeded!!\n"); + printk("Skipping remaining sources.\n"); + --mp_irq_entries; + } + mpt+=sizeof(*m); count+=sizeof(*m); break; @@ -514,7 +530,7 @@ * set some other information about it. */ nlong = boot_cpu_id<<24; /* Dummy 'self' for bootup */ - cpu_logical_map[0] = boot_cpu_id; + __cpu_logical_map[0] = boot_cpu_id; global_irq_holder = boot_cpu_id; current->processor = boot_cpu_id; @@ -622,7 +638,7 @@ /* * Set up our APIC timer. */ - setup_APIC_clock (); + setup_APIC_clock(); sti(); /* @@ -705,7 +721,7 @@ panic("No idle process for CPU %d", i); idle->processor = i; - cpu_logical_map[cpucount] = i; + __cpu_logical_map[cpucount] = i; cpu_number_map[i] = cpucount; /* start_eip had better be page-aligned! */ @@ -849,7 +865,7 @@ /* number CPUs logically, starting from 1 (BSP is 0) */ #if 0 cpu_number_map[i] = cpucount; - cpu_logical_map[cpucount] = i; + __cpu_logical_map[cpucount] = i; #endif printk("OK.\n"); printk("CPU%d: ", i); @@ -862,8 +878,14 @@ else printk("Not responding.\n"); } - } SMP_PRINTK(("CPU has booted.\n")); + } + else + { + __cpu_logical_map[cpucount] = -1; + cpu_number_map[i] = -1; + cpucount--; + } swapper_pg_dir[0]=maincfg; local_flush_tlb(); @@ -915,6 +937,7 @@ if (!smp_found_config) { printk(KERN_NOTICE "SMP motherboard not detected. Using dummy APIC emulation.\n"); + io_apic_irqs = 0; return; } @@ -1014,9 +1037,11 @@ * Make sure we unmap all failed CPUs */ - if (cpu_number_map[i] == -1) + if (cpu_number_map[i] == -1 && (cpu_present_map & (1 << i))) { + printk("CPU #%d not responding. Removing from cpu_present_map.\n",i); cpu_present_map &= ~(1 << i); - } + } + } /* * Cleanup possible dangling ends... @@ -1075,25 +1100,67 @@ if(smp_b_stepping) printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n"); SMP_PRINTK(("Boot done.\n")); + + /* + * Here we can be sure that there is an IO-APIC in the system, lets + * go and set it up: + */ + setup_IO_APIC(); +} + + +void send_IPI (int dest, int vector) +{ + unsigned long cfg; + unsigned long flags; + + __save_flags(flags); + __cli(); + + /* + * prepare target chip field + */ + + cfg = apic_read(APIC_ICR2) & 0x00FFFFFF; + apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(dest)); + + cfg = apic_read(APIC_ICR); + cfg &= ~0xFDFFF; + cfg |= APIC_DEST_FIELD|APIC_DEST_DM_FIXED|vector; + cfg |= dest; + + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ + + apic_write(APIC_ICR, cfg); + __restore_flags(flags); +} + +void funny (void) +{ + send_IPI(APIC_DEST_ALLBUT,0x30 /*IO_APIC_VECTOR(11)*/); + for(;;)__cli(); } /* - * A non wait message cannot pass data or cpu source info. This current setup - * is only safe because the kernel lock owner is the only person who can send a message. + * A non wait message cannot pass data or cpu source info. This current setup + * is only safe because the kernel lock owner is the only person who can send + * a message. + * + * Wrapping this whole block in a spinlock is not the safe answer either. A + * processor may get stuck with irq's off waiting to send a message and thus + * not replying to the person spinning for a reply.... * - * Wrapping this whole block in a spinlock is not the safe answer either. A processor may - * get stuck with irq's off waiting to send a message and thus not replying to the person - * spinning for a reply.... - * - * In the end flush tlb ought to be the NMI and a very very short function (to avoid the old - * IDE disk problems), and other messages sent with IRQ's enabled in a civilised fashion. That - * will also boost performance. + * In the end flush tlb ought to be the NMI and a very very short function + * (to avoid the old IDE disk problems), and other messages sent with IRQ's + * enabled in a civilised fashion. That will also boost performance. */ void smp_message_pass(int target, int msg, unsigned long data, int wait) { - unsigned long flags; unsigned long cfg; + unsigned long dest = 0; unsigned long target_map; int p=smp_processor_id(); int irq; @@ -1135,11 +1202,11 @@ } /* - * Sanity check we don't re-enter this across CPU's. Only the kernel - * lock holder may send messages. For a STOP_CPU we are bringing the - * entire box to the fastest halt we can.. A reschedule carries - * no data and can occur during a flush.. guess what panic - * I got to notice this bug... + * Sanity check we don't re-enter this across CPU's. Only the kernel + * lock holder may send messages. For a STOP_CPU we are bringing the + * entire box to the fastest halt we can.. A reschedule carries + * no data and can occur during a flush.. guess what panic + * I got to notice this bug... */ /* @@ -1152,11 +1219,11 @@ p, msg, target);*/ /* - * Wait for the APIC to become ready - this should never occur. Its - * a debugging check really. + * Wait for the APIC to become ready - this should never occur. Its + * a debugging check really. */ - while(ct<1000) + while (ct<1000) { cfg=apic_read(APIC_ICR); if(!(cfg&(1<<12))) @@ -1173,49 +1240,32 @@ printk("CPU #%d: previous IPI still not cleared after 10mS\n", p); /* - * Program the APIC to deliver the IPI - */ - - __save_flags(flags); - __cli(); - cfg=apic_read(APIC_ICR2); - cfg&=0x00FFFFFF; - apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(target)); /* Target chip */ - cfg=apic_read(APIC_ICR); - cfg&=~0xFDFFF; /* Clear bits */ - cfg|=APIC_DEST_FIELD|APIC_DEST_DM_FIXED|irq; /* Send an IRQ 13 */ - - /* * Set the target requirement */ if(target==MSG_ALL_BUT_SELF) { - cfg|=APIC_DEST_ALLBUT; + dest=APIC_DEST_ALLBUT; target_map=cpu_present_map; cpu_callin_map[0]=(1<pid) { update_one_process(p, 1, user, system, cpu); @@ -1353,28 +1403,22 @@ p->counter = 0; need_resched = 1; } - if (p->priority < DEF_PRIORITY) + if (p->priority < DEF_PRIORITY) { kstat.cpu_nice += user; - else + kstat.per_cpu_nice[cpu] += user; + } else { kstat.cpu_user += user; + kstat.per_cpu_user[cpu] += user; + } kstat.cpu_system += system; kstat.per_cpu_system[cpu] += system; - } else { -#ifdef __SMP_PROF__ - if (test_bit(cpu,&smp_idle_map)) - smp_idle_count[cpu]++; -#endif } prof_counter[cpu]=prof_multiplier[cpu]; - irq_exit(cpu, 0); } -#ifdef __SMP_PROF__ - smp_local_timer_ticks[cpu]++; -#endif /* * We take the 'long' return path, and there every subsystem * grabs the apropriate locks (kernel lock/ irq lock). @@ -1403,7 +1447,9 @@ * want to be able to accept NMI tlb invalidates * during this time. */ + spin_lock(&irq_controller_lock); ack_APIC_irq (); + spin_unlock(&irq_controller_lock); smp_local_timer_interrupt(regs); } @@ -1416,10 +1462,12 @@ int cpu = smp_processor_id(); ack_APIC_irq(); + for (;;) __cli(); /* * This looks silly, but we actually do need to wait * for the global interrupt lock. */ + printk("huh, this is used, where???\n"); irq_enter(cpu, 0); need_resched = 1; irq_exit(cpu, 0); @@ -1666,7 +1714,9 @@ /* * We ACK the APIC, just in case there is something pending. */ + ack_APIC_irq (); + restore_flags(flags); } diff -ur --new-file old/linux/arch/i386/kernel/sys_i386.c new/linux/arch/i386/kernel/sys_i386.c --- old/linux/arch/i386/kernel/sys_i386.c Mon Dec 8 23:58:44 1997 +++ new/linux/arch/i386/kernel/sys_i386.c Sat Feb 28 00:34:40 1998 @@ -65,14 +65,17 @@ lock_kernel(); if (copy_from_user(&a, arg, sizeof(a))) - goto out; + goto out; if (!(a.flags & MAP_ANONYMOUS)) { error = -EBADF; - if (a.fd >= NR_OPEN || !(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/i386/kernel/time.c new/linux/arch/i386/kernel/time.c --- old/linux/arch/i386/kernel/time.c Mon Dec 22 02:27:18 1997 +++ new/linux/arch/i386/kernel/time.c Sun Jan 25 19:05:46 1998 @@ -248,6 +248,7 @@ return count; } +#ifndef CONFIG_APM /* * this is only used if we have fast gettimeoffset: */ @@ -255,6 +256,7 @@ { do_gettimeofday(tv); } +#endif static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; diff -ur --new-file old/linux/arch/i386/kernel/trampoline.S new/linux/arch/i386/kernel/trampoline.S --- old/linux/arch/i386/kernel/trampoline.S Mon Dec 1 19:34:10 1997 +++ new/linux/arch/i386/kernel/trampoline.S Thu Mar 12 19:33:21 1998 @@ -28,6 +28,7 @@ #include #include +#include .data @@ -62,7 +63,7 @@ gdt_48: .word 0x0800 # gdt limit = 2048, 256 GDT entries - .long gdt_table-0xc0000000 # gdt base = gdt (first SMP CPU) + .long gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU) .globl SYMBOL_NAME(trampoline_end) SYMBOL_NAME_LABEL(trampoline_end) 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 Mon Dec 22 02:27:18 1997 +++ new/linux/arch/i386/kernel/traps.c Sat Feb 21 03:28:21 1998 @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff -ur --new-file old/linux/arch/i386/lib/checksum.c new/linux/arch/i386/lib/checksum.c --- old/linux/arch/i386/lib/checksum.c Wed Oct 15 03:24:09 1997 +++ new/linux/arch/i386/lib/checksum.c Tue Mar 17 02:48:06 1998 @@ -208,7 +208,7 @@ # Exception handler: ################################################ # -.section .fixup, \"a\" # +.section .fixup, \"ax\" # # 6000: # # diff -ur --new-file old/linux/arch/i386/lib/usercopy.c new/linux/arch/i386/lib/usercopy.c --- old/linux/arch/i386/lib/usercopy.c Sun Jan 11 06:28:41 1998 +++ new/linux/arch/i386/lib/usercopy.c Sat Jan 24 01:34:36 1998 @@ -89,7 +89,7 @@ " .long 0b,3b\n" \ " .long 1b,2b\n" \ ".previous" \ - : "=c"(size) \ + : "=&c"(size) \ : "r"(size & 3), "0"(size / 4), "D"(addr), "a"(0) \ : "di") diff -ur --new-file old/linux/arch/i386/math-emu/fpu_entry.c new/linux/arch/i386/math-emu/fpu_entry.c --- old/linux/arch/i386/math-emu/fpu_entry.c Wed Dec 10 02:57:09 1997 +++ new/linux/arch/i386/math-emu/fpu_entry.c Sun Jan 25 20:01:48 1998 @@ -728,11 +728,11 @@ FPU_verify_area(VERIFY_WRITE, d, 7*4 + 8*10); #ifdef PECULIAR_486 S387->cwd &= ~0xe080; - /* An 80486 sets all the reserved bits to 1. */ - S387->cwd |= 0xffff0000; + /* An 80486 sets nearly all of the reserved bits to 1. */ + S387->cwd |= 0xffff0040; S387->swd = sstatus_word() | 0xffff0000; S387->twd |= 0xffff0000; - S387->fcs |= 0xf8000000; + S387->fcs &= ~0xf8000000; S387->fos |= 0xffff0000; #endif PECULIAR_486 __copy_to_user(d, &S387->cwd, 7*4); diff -ur --new-file old/linux/arch/i386/math-emu/get_address.c new/linux/arch/i386/math-emu/get_address.c --- old/linux/arch/i386/math-emu/get_address.c Wed Dec 10 02:57:09 1997 +++ new/linux/arch/i386/math-emu/get_address.c Sun Jan 25 20:01:48 1998 @@ -134,8 +134,8 @@ static unsigned long vm86_segment(u_char segment, - unsigned short *selector) -{ + struct address *addr) +{ segment--; #ifdef PARANOID if ( segment > PREFIX_SS_ ) @@ -144,14 +144,14 @@ math_abort(FPU_info,SIGSEGV); } #endif PARANOID - *selector = VM86_REG_(segment); + addr->selector = VM86_REG_(segment); return (unsigned long)VM86_REG_(segment) << 4; } /* This should work for 16 and 32 bit protected mode. */ static long pm_address(u_char FPU_modrm, u_char segment, - unsigned short *selector, long offset) + struct address *addr, long offset) { struct desc_struct descriptor; unsigned long base_address, limit, address, seg_top; @@ -172,13 +172,17 @@ /* fs and gs aren't used by the kernel, so they still have their user-space values. */ case PREFIX_FS_-1: - __asm__("mov %%fs,%0":"=r" (*selector)); + /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register + in the assembler statement. */ + __asm__("mov %%fs,%0":"=r" ((unsigned short)addr->selector)); break; case PREFIX_GS_-1: - __asm__("mov %%gs,%0":"=r" (*selector)); + /* The cast is needed here to get gcc 2.8.0 to use a 16 bit register + in the assembler statement. */ + __asm__("mov %%gs,%0":"=r" ((unsigned short)addr->selector)); break; default: - *selector = PM_REG_(segment); + addr->selector = PM_REG_(segment); } descriptor = LDT_DESCRIPTOR(PM_REG_(segment)); @@ -312,13 +316,12 @@ case 0: break; case VM86: - address += vm86_segment(addr_modes.override.segment, - (unsigned short *)&(addr->selector)); + address += vm86_segment(addr_modes.override.segment, addr); break; case PM16: case SEG32: address = pm_address(FPU_modrm, addr_modes.override.segment, - (unsigned short *)&(addr->selector), address); + addr, address); break; default: EXCEPTION(EX_INTERNAL|0x133); @@ -427,13 +430,12 @@ case 0: break; case VM86: - address += vm86_segment(addr_modes.override.segment, - (unsigned short *)&(addr->selector)); + address += vm86_segment(addr_modes.override.segment, addr); break; case PM16: case SEG32: address = pm_address(FPU_modrm, addr_modes.override.segment, - (unsigned short *)&(addr->selector), address); + addr, address); break; default: EXCEPTION(EX_INTERNAL|0x131); diff -ur --new-file old/linux/arch/i386/math-emu/reg_ld_str.c new/linux/arch/i386/math-emu/reg_ld_str.c --- old/linux/arch/i386/math-emu/reg_ld_str.c Wed Dec 10 02:57:09 1997 +++ new/linux/arch/i386/math-emu/reg_ld_str.c Sun Jan 25 20:01:48 1998 @@ -1329,11 +1329,11 @@ FPU_verify_area(VERIFY_WRITE, d, 7*4); #ifdef PECULIAR_486 control_word &= ~0xe080; - /* An 80486 sets all the reserved bits to 1. */ - control_word |= 0xffff0000; + /* An 80486 sets nearly all of the reserved bits to 1. */ + control_word |= 0xffff0040; partial_status = status_word() | 0xffff0000; fpu_tag_word |= 0xffff0000; - I387.soft.fcs |= 0xf8000000; + I387.soft.fcs &= ~0xf8000000; I387.soft.fos |= 0xffff0000; #endif PECULIAR_486 __copy_to_user(d, &control_word, 7*4); diff -ur --new-file old/linux/arch/i386/mm/fault.c new/linux/arch/i386/mm/fault.c --- old/linux/arch/i386/mm/fault.c Wed Jan 7 21:04:52 1998 +++ new/linux/arch/i386/mm/fault.c Tue Jan 20 21:52:09 1998 @@ -20,6 +20,7 @@ #include #include #include +#include extern void die_if_kernel(const char *,struct pt_regs *,long); @@ -99,6 +100,8 @@ /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); + if (local_irq_count[smp_processor_id()]) + die_if_kernel("page fault from irq handler",regs,error_code); lock_kernel(); tsk = current; mm = tsk->mm; diff -ur --new-file old/linux/arch/i386/mm/init.c new/linux/arch/i386/mm/init.c --- old/linux/arch/i386/mm/init.c Mon Jan 12 23:33:20 1998 +++ new/linux/arch/i386/mm/init.c Thu Mar 12 00:10:39 1998 @@ -204,8 +204,8 @@ /* unmap the original low memory mappings */ pgd_val(pg_dir[0]) = 0; - /* Map whole memory from 0xC0000000 */ - pg_dir += 768; + /* Map whole memory from PAGE_OFFSET */ + pg_dir += USER_PGD_PTRS; while (address < end_mem) { /* * If we're running on a Pentium CPU, we can use the 4MB diff -ur --new-file old/linux/arch/i386/vmlinux.lds new/linux/arch/i386/vmlinux.lds --- old/linux/arch/i386/vmlinux.lds Wed May 14 07:41:01 1997 +++ new/linux/arch/i386/vmlinux.lds Thu Mar 12 00:10:39 1998 @@ -1,12 +1,13 @@ /* ld script to make i386 Linux kernel * Written by Martin Mares */ +INCLUDE arch/i386/.kernel_offset.lds OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) ENTRY(_start) SECTIONS { - . = 0xc0100000; + . = __kernel_offset__ + 0x100000; _text = .; /* Text and read-only data */ .text : { *(.text) diff -ur --new-file old/linux/arch/m68k/Makefile new/linux/arch/m68k/Makefile --- old/linux/arch/m68k/Makefile Thu Jul 31 22:09:16 1997 +++ new/linux/arch/m68k/Makefile Fri Feb 13 01:30:11 1998 @@ -26,6 +26,7 @@ LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds +# without -fno-strength-reduce the 53c7xx.c driver fails ;-( CFLAGS += -pipe -fno-strength-reduce -ffixed-a2 ifdef CONFIG_OPTIMIZE_040 @@ -33,7 +34,7 @@ endif ifdef CONFIG_OPTIMIZE_060 -CFLAGS := $(CFLAGS) -m68020-40 +CFLAGS := $(CFLAGS) -m68060 endif ifdef CONFIG_KGDB @@ -63,10 +64,14 @@ SUBDIRS := $(SUBDIRS) arch/m68k/mac endif -ifdef CONFIG_VT -# add in console.a after {amiga,atari}.o that need it -CORE_FILES := $(CORE_FILES) arch/m68k/console/console.a -SUBDIRS := $(SUBDIRS) arch/m68k/console +ifdef CONFIG_APOLLO +CORE_FILES := $(CORE_FILES) arch/m68k/apollo/apollo.o +SUBDIRS := $(SUBDIRS) arch/m68k/apollo +endif + +ifdef CONFIG_MVME16x +CORE_FILES := $(CORE_FILES) arch/m68k/mvme16x/mvme16x.o +SUBDIRS := $(SUBDIRS) arch/m68k/mvme16x endif ifdef CONFIG_M68040 @@ -98,9 +103,6 @@ else gzip -9c vmlinux >vmlinux.gz endif - -bootstrap: dummy - @$(MAKEBOOT) bootstrap archclean: rm -f vmlinux.gz diff -ur --new-file old/linux/arch/m68k/amiga/Makefile new/linux/arch/m68k/amiga/Makefile --- old/linux/arch/m68k/amiga/Makefile Thu Apr 24 04:01:14 1997 +++ new/linux/arch/m68k/amiga/Makefile Fri Feb 13 01:30:12 1998 @@ -8,16 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := amiga.o -O_OBJS := config.o amikeyb.o amiints.o cia.o \ - chipram.o amisound.o amifb.o zorro.o +O_OBJS := config.o amiints.o cia.o chipram.o amisound.o zorro.o OX_OBJS := amiga_ksyms.o - -ifdef CONFIG_FB_CYBER -O_OBJS := $(O_OBJS) cyberfb.o -endif - -ifdef CONFIG_FB_RETINAZ3 -O_OBJS := $(O_OBJS) retz3fb.o -endif include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/m68k/amiga/amiga_ksyms.c new/linux/arch/m68k/amiga/amiga_ksyms.c --- old/linux/arch/m68k/amiga/amiga_ksyms.c Thu Apr 24 04:01:14 1997 +++ new/linux/arch/m68k/amiga/amiga_ksyms.c Wed Mar 18 06:15:40 1998 @@ -1,8 +1,8 @@ -#include #include #include #include #include +#include extern volatile u_short amiga_audio_min_period; extern u_short amiga_audio_period; @@ -25,3 +25,7 @@ EXPORT_SYMBOL(zorro_config_board); EXPORT_SYMBOL(zorro_unconfig_board); EXPORT_SYMBOL(zorro_unused_z2ram); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff -ur --new-file old/linux/arch/m68k/amiga/amiints.c new/linux/arch/m68k/amiga/amiints.c --- old/linux/arch/m68k/amiga/amiints.c Wed May 14 07:41:01 1997 +++ new/linux/arch/m68k/amiga/amiints.c Fri Feb 13 01:30:12 1998 @@ -331,7 +331,7 @@ inline void amiga_do_irq(int irq, struct pt_regs *fp) { - kstat.interrupts[SYS_IRQS + irq]++; + kstat.irqs[0][SYS_IRQS + irq]++; ami_irq_list[irq]->handler(irq, ami_irq_list[irq]->dev_id, fp); } @@ -340,7 +340,7 @@ irq_node_t *node, *slow_nodes; unsigned short flags; - kstat.interrupts[SYS_IRQS + irq]++; + kstat.irqs[0][SYS_IRQS + irq]++; if (server->count++) server->reentrance = 1; /* serve first fast and normal handlers */ @@ -489,7 +489,7 @@ if (node->flags & IRQ_FLG_STD) continue; len += sprintf(buf+len, "ami %2d: %10u ", i, - kstat.interrupts[SYS_IRQS + i]); + kstat.irqs[0][SYS_IRQS + i]); do { if (ami_servers[i]) { if (node->flags & IRQ_FLG_FAST) diff -ur --new-file old/linux/arch/m68k/amiga/cia.c new/linux/arch/m68k/amiga/cia.c --- old/linux/arch/m68k/amiga/cia.c Wed May 14 07:41:01 1997 +++ new/linux/arch/m68k/amiga/cia.c Fri Feb 13 01:30:12 1998 @@ -145,7 +145,7 @@ custom.intreq = base->int_mask; for (i = 0; i < CIA_IRQS; i++, irq++, mach_irq++) { if (ints & 1) { - kstat.interrupts[irq]++; + kstat.irqs[0][irq]++; base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp); } ints >>= 1; @@ -181,7 +181,7 @@ for (i = 0; i < CIA_IRQS; i++) { if (!(base->irq_list[i].flags & IRQ_FLG_STD)) { len += sprintf(buf+len, "cia %2d: %10d ", j + i, - kstat.interrupts[SYS_IRQS + j + i]); + kstat.irqs[0][SYS_IRQS + j + i]); if (base->irq_list[i].flags & IRQ_FLG_LOCK) len += sprintf(buf+len, "L "); else diff -ur --new-file old/linux/arch/m68k/amiga/config.c new/linux/arch/m68k/amiga/config.c --- old/linux/arch/m68k/amiga/config.c Mon Jul 7 17:18:53 1997 +++ new/linux/arch/m68k/amiga/config.c Fri Feb 13 01:30:12 1998 @@ -31,13 +31,13 @@ #include #include -u_long amiga_model; -u_long amiga_eclock; -u_long amiga_masterclock; -u_long amiga_colorclock; -u_long amiga_chipset; -u_char amiga_vblank; -u_char amiga_psfreq; +unsigned long amiga_model; +unsigned long amiga_eclock; +unsigned long amiga_masterclock; +unsigned long amiga_colorclock; +unsigned long amiga_chipset; +unsigned char amiga_vblank; +unsigned char amiga_psfreq; struct amiga_hw_present amiga_hw_present; static const char *amiga_models[] = { @@ -54,8 +54,10 @@ /* amiga specific irq functions */ extern void amiga_init_IRQ (void); extern void (*amiga_default_handler[]) (int, void *, struct pt_regs *); -extern int amiga_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id); +extern int amiga_request_irq (unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, + void *dev_id); extern void amiga_free_irq (unsigned int irq, void *dev_id); extern void amiga_enable_irq (unsigned int); extern void amiga_disable_irq (unsigned int); @@ -69,28 +71,50 @@ static int amiga_hwclk (int, struct hwclk_time *); static int amiga_set_clock_mmss (unsigned long); extern void amiga_mksound( unsigned int count, unsigned int ticks ); -#ifdef CONFIG_BLK_DEV_FD -extern int amiga_floppy_init (void); +#ifdef CONFIG_AMIGA_FLOPPY extern void amiga_floppy_setup(char *, int *); #endif static void amiga_reset (void); -static void amiga_wait_key(void); +static int amiga_wait_key (struct console *co); extern struct consw fb_con; -extern struct fb_info *amiga_fb_init(long *); extern void zorro_init(void); extern void amiga_init_sound(void); static void amiga_savekmsg_init(void); -static void amiga_mem_console_write(const char *b, unsigned int count); -static void amiga_serial_console_write(const char *s, unsigned int count); +static void amiga_mem_console_write(struct console *co, const char *b, + unsigned int count); +void amiga_serial_console_write(struct console *co, const char *s, + unsigned int count); static void amiga_debug_init(void); - -extern void amiga_video_setup(char *, int *); -extern void amiga_init_sound(void); +#ifdef CONFIG_HEARTBEAT +static void amiga_heartbeat(int on); +#endif static struct console amiga_console_driver = { - NULL, NULL, amiga_wait_key + "debug", + NULL, /* write */ + NULL, /* read */ + NULL, /* device */ + amiga_wait_key, /* wait_key */ + NULL, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, + -1, + 0, + NULL }; +#ifdef CONFIG_MAGIC_SYSRQ +static char amiga_sysrq_xlate[128] = + "\0001234567890-=\\\000\000" /* 0x00 - 0x0f */ + "qwertyuiop[]\000123" /* 0x10 - 0x1f */ + "asdfghjkl;'\000\000456" /* 0x20 - 0x2f */ + "\000zxcvbnm,./\000+789" /* 0x30 - 0x3f */ + " \177\t\r\r\000\177\000\000\000-\000\000\000\000\000" /* 0x40 - 0x4f */ + "\000\201\202\203\204\205\206\207\210\211()/*+\000" /* 0x50 - 0x5f */ + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x60 - 0x6f */ + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ +#endif + extern void (*kd_mksound)(unsigned int, unsigned int); /* @@ -100,7 +124,7 @@ int amiga_parse_bootinfo(const struct bi_record *record) { int unknown = 0; - const u_long *data = record->data; + const unsigned long *data = record->data; switch (record->tag) { case BI_AMIGA_MODEL: @@ -120,11 +144,11 @@ break; case BI_AMIGA_VBLANK: - amiga_vblank = *(const u_char *)data; + amiga_vblank = *(const unsigned char *)data; break; case BI_AMIGA_PSFREQ: - amiga_psfreq = *(const u_char *)data; + amiga_psfreq = *(const unsigned char *)data; break; case BI_AMIGA_AUTOCON: @@ -147,10 +171,10 @@ } /* - * Setup the Amiga configuration info + * Identify builtin hardware */ -__initfunc(void config_amiga(void)) +__initfunc(static void amiga_identify(void)) { /* Fill in some default values, if necessary */ if (amiga_eclock == 0) @@ -158,8 +182,6 @@ memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); - amiga_debug_init(); - printk("Amiga hardware found: "); if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) printk("[%s] ", amiga_models[amiga_model-AMI_500]); @@ -171,6 +193,7 @@ case AMI_600: case AMI_1200: AMIGAHW_SET(A1200_IDE); + AMIGAHW_SET(PCMCIA); case AMI_500: case AMI_500PLUS: case AMI_1000: @@ -300,11 +323,22 @@ AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); - if (AMIGAHW_SET(ZORRO)) - printk("ZORRO%s ", AMIGAHW_SET(ZORRO3) ? "3" : ""); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); + if (AMIGAHW_PRESENT(ZORRO)) + printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); printk("\n"); #undef AMIGAHW_ANNOUNCE +} + + /* + * Setup the Amiga configuration info + */ + +__initfunc(void config_amiga(void)) +{ + amiga_debug_init(); + amiga_identify(); mach_sched_init = amiga_sched_init; mach_keyb_init = amiga_keyb_init; @@ -338,15 +372,21 @@ mach_hwclk = amiga_hwclk; mach_set_clock_mmss = amiga_set_clock_mmss; -#ifdef CONFIG_BLK_DEV_FD - mach_floppy_init = amiga_floppy_init; +#ifdef CONFIG_AMIGA_FLOPPY mach_floppy_setup = amiga_floppy_setup; #endif mach_reset = amiga_reset; conswitchp = &fb_con; - mach_fb_init = amiga_fb_init; - mach_video_setup = amiga_video_setup; kd_mksound = amiga_mksound; +#ifdef CONFIG_MAGIC_SYSRQ + mach_sysrq_key = 0x5f; /* HELP */ + mach_sysrq_shift_state = 0x03; /* SHIFT+ALTGR */ + mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */ + mach_sysrq_xlate = amiga_sysrq_xlate; +#endif +#ifdef CONFIG_HEARTBEAT + mach_heartbeat = amiga_heartbeat; +#endif /* Fill in the clock values (based on the 700 kHz E-Clock) */ amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ @@ -357,15 +397,51 @@ /* ensure that the DMA master bit is set */ custom.dmacon = DMAF_SETCLR | DMAF_MASTER; + /* don't use Z2 RAM as system memory on Z3 capable machines */ + if (AMIGAHW_PRESENT(ZORRO3)) { + int i, j; + unsigned long z2mem = 0; + for (i = 0; i < m68k_num_memory; i++) + if (m68k_memory[i].addr < 16*1024*1024) { + if (i == 0) { + /* don't cut off the branch we're sitting on */ + printk("Warning: kernel runs in Zorro II memory\n"); + continue; + } + z2mem += m68k_memory[i].size; + m68k_num_memory--; + for (j = i; j < m68k_num_memory; j++) + m68k_memory[j] = m68k_memory[j+1]; + } + if (z2mem) + printk("%ldK of Zorro II memory will not be used as system memory\n", + z2mem>>10); + } + /* initialize chipram allocator */ amiga_chip_init (); + /* debugging using chipram */ + if (!strcmp( m68k_debug_device, "mem" )){ + if (!AMIGAHW_PRESENT(CHIP_RAM)) + printk("Warning: no chipram present for debugging\n"); + else { + amiga_savekmsg_init(); + amiga_console_driver.write = amiga_mem_console_write; + register_console(&amiga_console_driver); + } + } + + /* our beloved beeper */ + if (AMIGAHW_PRESENT(AMI_AUDIO)) + amiga_init_sound(); + /* * if it is an A3000, set the magic bit that forces * a hard rekick */ if (AMIGAHW_PRESENT(MAGIC_REKICK)) - *(u_char *)ZTWO_VADDR(0xde0002) |= 0x80; + *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; zorro_init(); #ifdef CONFIG_ZORRO @@ -373,7 +449,7 @@ * Identify all known AutoConfig Expansion Devices */ zorro_identify(); -#endif /* CONFIG_ZORRO */ +#endif } static unsigned short jiffy_ticks; @@ -383,7 +459,7 @@ { jiffy_ticks = (amiga_eclock+HZ/2)/HZ; - ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ + ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ ciab.talo = jiffy_ticks % 256; ciab.tahi = jiffy_ticks / 256; @@ -392,7 +468,8 @@ * Please don't change this to use ciaa, as it interferes with the * SCSI code. We'll have to take a look at this later */ - request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK, "timer", NULL); + request_irq(IRQ_AMIGA_CIAB_TA, timer_routine, IRQ_FLG_LOCK, + "timer", NULL); /* start timer */ ciab.cra |= 0x11; } @@ -462,11 +539,12 @@ *monp = tod->month1 * 10 + tod->month2; *yearp = tod->year1 * 10 + tod->year2; - if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)) + if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){ if (!(tod->hour1 & TOD2000_HOUR1_PM) && *hourp == 12) *hourp = 0; else if ((tod->hour1 & TOD2000_HOUR1_PM) && *hourp != 12) *hourp += 12; + } tod->cntrl1 &= ~TOD2000_CNTRL1_HOLD; } @@ -521,11 +599,12 @@ t->mon = tod->month1 * 10 + tod->month2 - 1; t->year = tod->year1 * 10 + tod->year2; - if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)) + if (!(tod->cntrl3 & TOD2000_CNTRL3_24HMODE)){ if (!(tod->hour1 & TOD2000_HOUR1_PM) && t->hour == 12) t->hour = 0; else if ((tod->hour1 & TOD2000_HOUR1_PM) && t->hour != 12) t->hour += 12; + } } else { tod->second1 = t->sec / 10; tod->second2 = t->sec % 10; @@ -589,7 +668,7 @@ return 0; } -static void amiga_wait_key (void) +static int amiga_wait_key (struct console *co) { int i; @@ -613,6 +692,7 @@ if (ciaa.pra & 0x40) break; } + return 0; } void dbprintf(const char *fmt , ...) @@ -707,16 +787,17 @@ #define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */ struct savekmsg { - u_long magic1; /* SAVEKMSG_MAGIC1 */ - u_long magic2; /* SAVEKMSG_MAGIC2 */ - u_long magicptr; /* address of magic1 */ - u_long size; + unsigned long magic1; /* SAVEKMSG_MAGIC1 */ + unsigned long magic2; /* SAVEKMSG_MAGIC2 */ + unsigned long magicptr; /* address of magic1 */ + unsigned long size; char data[0]; }; static struct savekmsg *savekmsg = NULL; -static void amiga_mem_console_write(const char *s, unsigned int count) +static void amiga_mem_console_write(struct console *co, const char *s, + unsigned int count) { if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { memcpy(savekmsg->data+savekmsg->size, s, count); @@ -740,7 +821,8 @@ ; } -static void amiga_serial_console_write(const char *s, unsigned int count) +void amiga_serial_console_write(struct console *co, const char *s, + unsigned int count) { while (count--) { if (*s == '\n') @@ -752,19 +834,27 @@ #ifdef CONFIG_SERIAL_CONSOLE void amiga_serial_puts(const char *s) { - amiga_serial_console_write(s, strlen(s)); + amiga_serial_console_write(NULL, s, strlen(s)); +} + +int amiga_serial_console_wait_key(struct console *co) +{ + int ch; + + while (!(custom.intreqr & IF_RBF)) + barrier(); + ch = custom.serdatr & 0xff; + /* clear the interrupt, so that another character can be read */ + custom.intreq = IF_RBF; + return ch; } -void amiga_serial_gets(char *s, int len) +void amiga_serial_gets(struct console *co, char *s, int len) { int ch, cnt = 0; while (1) { - while (!(custom.intreqr & IF_RBF)) - barrier(); - ch = custom.serdatr & 0xff; - /* clear the interrupt, so that another character can be read */ - custom.intreq = IF_RBF; + ch = amiga_serial_console_wait_key(co); /* Check for backspace. */ if (ch == 8 || ch == 127) { @@ -803,17 +893,19 @@ if (!strcmp( m68k_debug_device, "ser" )) { /* no initialization required (?) */ amiga_console_driver.write = amiga_serial_console_write; - } else if (!strcmp( m68k_debug_device, "mem" )) { - amiga_savekmsg_init(); - amiga_console_driver.write = amiga_mem_console_write; + register_console(&amiga_console_driver); } - register_console(&amiga_console_driver); - - /* our beloved beeper */ - if (AMIGAHW_PRESENT(AMI_AUDIO)) - amiga_init_sound(); } +#ifdef CONFIG_HEARTBEAT +static void amiga_heartbeat(int on) +{ + if (on) + ciaa.pra &= ~2; + else + ciaa.pra |= 2; +} +#endif /* * Amiga specific parts of /proc @@ -888,6 +980,7 @@ AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); if (AMIGAHW_PRESENT(ZORRO)) len += sprintf(buffer+len, "\tZorro%s AutoConfig: %d Expansion Device%s\n", AMIGAHW_PRESENT(ZORRO3) ? " III" : "", diff -ur --new-file old/linux/arch/m68k/amiga/s3blit.h new/linux/arch/m68k/amiga/s3blit.h --- old/linux/arch/m68k/amiga/s3blit.h Mon May 20 06:54:25 1996 +++ new/linux/arch/m68k/amiga/s3blit.h Thu Jan 1 01:00:00 1970 @@ -1,74 +0,0 @@ -/* s3 commands */ -#define S3_BITBLT 0xc011 -#define S3_TWOPOINTLINE 0x2811 -#define S3_FILLEDRECT 0x40b1 - -#define S3_FIFO_EMPTY 0x0400 -#define S3_HDW_BUSY 0x0200 - -/* Enhanced register mapping (MMIO mode) */ - -#define S3_READ_SEL 0xbee8 /* offset f */ -#define S3_MULT_MISC 0xbee8 /* offset e */ -#define S3_ERR_TERM 0x92e8 -#define S3_FRGD_COLOR 0xa6e8 -#define S3_BKGD_COLOR 0xa2e8 -#define S3_PIXEL_CNTL 0xbee8 /* offset a */ -#define S3_FRGD_MIX 0xbae8 -#define S3_BKGD_MIX 0xb6e8 -#define S3_CUR_Y 0x82e8 -#define S3_CUR_X 0x86e8 -#define S3_DESTY_AXSTP 0x8ae8 -#define S3_DESTX_DIASTP 0x8ee8 -#define S3_MIN_AXIS_PCNT 0xbee8 /* offset 0 */ -#define S3_MAJ_AXIS_PCNT 0x96e8 -#define S3_CMD 0x9ae8 -#define S3_GP_STAT 0x9ae8 -#define S3_ADVFUNC_CNTL 0x4ae8 -#define S3_WRT_MASK 0xaae8 -#define S3_RD_MASK 0xaee8 - -/* Enhanced register mapping (Packed MMIO mode, write only) */ -#define S3_ALT_CURXY 0x8100 -#define S3_ALT_CURXY2 0x8104 -#define S3_ALT_STEP 0x8108 -#define S3_ALT_STEP2 0x810c -#define S3_ALT_ERR 0x8110 -#define S3_ALT_CMD 0x8118 -#define S3_ALT_MIX 0x8134 -#define S3_ALT_PCNT 0x8148 -#define S3_ALT_PAT 0x8168 - -/* Drawing modes */ -#define S3_NOTCUR 0x0000 -#define S3_LOGICALZERO 0x0001 -#define S3_LOGICALONE 0x0002 -#define S3_LEAVEASIS 0x0003 -#define S3_NOTNEW 0x0004 -#define S3_CURXORNEW 0x0005 -#define S3_NOT_CURXORNEW 0x0006 -#define S3_NEW 0x0007 -#define S3_NOTCURORNOTNEW 0x0008 -#define S3_CURORNOTNEW 0x0009 -#define S3_NOTCURORNEW 0x000a -#define S3_CURORNEW 0x000b -#define S3_CURANDNEW 0x000c -#define S3_NOTCURANDNEW 0x000d -#define S3_CURANDNOTNEW 0x000e -#define S3_NOTCURANDNOTNEW 0x000f - -#define S3_CRTC_ADR 0x03d4 -#define S3_CRTC_DATA 0x03d5 - -#define S3_REG_LOCK2 0x39 -#define S3_HGC_MODE 0x45 - -#define S3_HWGC_ORGX_H 0x46 -#define S3_HWGC_ORGX_L 0x47 -#define S3_HWGC_ORGY_H 0x48 -#define S3_HWGC_ORGY_L 0x49 -#define S3_HWGC_DX 0x4e -#define S3_HWGC_DY 0x4f - - -#define S3_LAW_CTL 0x58 diff -ur --new-file old/linux/arch/m68k/amiga/zorro.c new/linux/arch/m68k/amiga/zorro.c --- old/linux/arch/m68k/amiga/zorro.c Thu Jul 31 22:09:16 1997 +++ new/linux/arch/m68k/amiga/zorro.c Fri Feb 13 01:30:12 1998 @@ -13,996 +13,1221 @@ #include #include #include -#include -#include #include #include #include +#include #ifdef CONFIG_ZORRO - /* - * Zorro Expansion Device Manufacturers and Products - */ + /* + * Zorro Expansion Device Manufacturers and Products + */ struct Manufacturer { - char *Name; - u_short ID; - u_short NumProd; - struct Product *Products; + const char *Name; + u_short Manuf; + u_short NumProd; + const struct Product *Products; }; struct Product { - char *Name; - u_char ID; + const char *Name; + u_char Class; + u_char Prod; }; struct GVP_Product { - char *Name; - enum GVP_ident ID; + const char *Name; + u_char Class; + u_char EPC; }; - /* - * Macro's to make life easier - */ - -#define BEGIN_PROD(id) static struct Product Prod_##id[] = { -#define PROD(name, id) \ - { name, PROD_##id }, - -#define BEGIN_GVP_PROD static struct GVP_Product Ext_Prod_GVP[] = { -#define GVP_PROD(name, id) \ - { name, GVP_##id }, + /* + * Macro's to make life easier + */ + +#define ARRAYSIZE(x) (sizeof(x)/sizeof(*(x))) + +#define BEGIN_PROD(id) \ + static struct Product Prod_##id[] = { +#define PROD(name, class, id) \ + { name, ZORRO_CLASS_##class, ZORRO_PROD(ZORRO_PROD_##id) }, + +#define BEGIN_GVP_PROD \ + static struct GVP_Product Ext_Prod_GVP[] = { +#define GVP_PROD(name, class, id) \ + { name, ZORRO_CLASS_##class, ZORRO_EPC(ZORRO_PROD_##id) }, -#define BEGIN_MANUF static struct Manufacturer Manufacturers[] = { +#define BEGIN_MANUF \ + static struct Manufacturer Manufacturers[] = { #define MANUF(name, id) \ - { name, MANUF_##id, sizeof(Prod_##id)/sizeof(struct Product), Prod_##id }, + { name, ZORRO_MANUF_##id, ARRAYSIZE(Prod_##id), Prod_##id }, -#define END }; +#define END \ + }; - /* - * Known Zorro Expansion Devices - * - * Warning: Make sure the Manufacturer and Product names are not too - * long (max. 80 characters per board identification line) - */ + /* + * Recognized Zorro Expansion Devices + */ + +BEGIN_PROD(PACIFIC_PERIPHERALS) + PROD("SE 2000 A500", HD, PACIFIC_PERIPHERALS_SE_2000_A500) + PROD(NULL, SCSI, PACIFIC_PERIPHERALS_SCSI) +END -BEGIN_PROD(PACIFIC) - PROD("SE 2000 A500", SE_2000_A500) - PROD("HD Controller", PACIFIC_HD) +BEGIN_PROD(MACROSYSTEMS_USA_2) + PROD("Warp Engine", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE) END -BEGIN_PROD(KUPKE) - PROD("Golem RAM Box 2MB", GOLEM_BOX_2) +BEGIN_PROD(KUPKE_1) + PROD("Golem RAM Box 2MB", RAM, KUPKE_GOLEM_RAM_BOX_2MB) END BEGIN_PROD(MEMPHIS) - PROD("Stormbringer", STORMBRINGER) + PROD("Stormbringer", TURBO, MEMPHIS_STORMBRINGER) END BEGIN_PROD(3_STATE) - PROD("Megamix 2000 RAM", MEGAMIX_2000) + PROD("Megamix 2000", RAM, 3_STATE_MEGAMIX_2000) +END + +BEGIN_PROD(COMMODORE_BRAUNSCHWEIG) + PROD("A2088 XT/A2286 AT", BRIDGE, CBM_A2088_A2286) + PROD("A2286 AT", BRIDGE, CBM_A2286) + PROD("A4091", SCSI, CBM_A4091_1) + PROD("A2386-SX", BRIDGE, CBM_A2386SX_1) +END + +BEGIN_PROD(COMMODORE_WEST_CHESTER_1) + PROD("A2090/A2090A", SCSI, CBM_A2090A) + PROD("A590/A2091", SCSI, CBM_A590_A2091_1) + PROD("A590/A2091", SCSI, CBM_A590_A2091_2) + PROD("A2090B 2090 Autoboot", SCSI, CBM_A2090B) + PROD("A2060", ARCNET, CBM_A2060) + PROD("A590/A2052/A2058/A2091", RAM, CBM_A590_A2052_A2058_A2091) + PROD("A560", RAM, CBM_A560_RAM) + PROD("A2232 Prototype", MULTIIO, CBM_A2232_PROTOTYPE) + PROD("A2232", MULTIIO, CBM_A2232) + PROD("A2620 68020/RAM", TURBO_RAM, CBM_A2620) + PROD("A2630 68030/RAM", TURBO_RAM, CBM_A2630) + PROD("A4091", SCSI, CBM_A4091_2) + PROD("A2065", ETHERNET, CBM_A2065_1) + PROD("Romulator Card", UNKNOWN, CBM_ROMULATOR) + PROD("A3000 Test Fixture", MISC, CBM_A3000_TEST_FIXTURE) + PROD("A2386-SX", BRIDGE, CBM_A2386SX_2) + PROD("A2065", ETHERNET, CBM_A2065_2) +END + +BEGIN_PROD(COMMODORE_WEST_CHESTER_2) + PROD("A2090/A2090A Combitec/MacroSystem", SCSI, CBM_A2090A_CM) +END + +BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2) + PROD("EXP8000", RAM, PPS_EXP8000) +END + +BEGIN_PROD(KOLFF_COMPUTER_SUPPLIES) + PROD("KCS Power PC Board", BRIDGE, KCS_POWER_PC_BOARD) END -BEGIN_PROD(COMMODORE2) - PROD("A2088 XT Bridgeboard", A2088) - PROD("A2286 AT Bridgeboard", A2286) - PROD("A4091 SCSI Controller", A4091_2) - PROD("A2386-SX Bridgeboard", A2386SX) -END - -BEGIN_PROD(COMMODORE) - PROD("A2090/A2090A HD Controller", A2090A) - PROD("A590 SCSI Controller", A590) - PROD("A2091 SCSI Controller", A2091) - PROD("A2090B 2090 Autoboot Card", A2090B) - PROD("A2060 Arcnet Card", ARCNET) - PROD("A2052/58.RAM | 590/2091.RAM", CBMRAM) - PROD("A560 Memory Module", A560RAM) - PROD("A2232 Serial Prototype", A2232PROTO) - PROD("A2232 Serial Production", A2232) - PROD("A2620 68020/RAM Card", A2620) - PROD("A2630 68030/RAM Card", A2630) - PROD("A4091 SCSI Controller", A4091) - PROD("A2065 Ethernet Card", A2065_2) - PROD("Romulator Card", ROMULATOR) - PROD("A3000 Test Fixture", A3000TESTFIX) - PROD("A2386-SX Bridgeboard", A2386SX_2) - PROD("A2065 Ethernet Card", A2065) -END - -BEGIN_PROD(COMMODORE3) - PROD("A2090A Combitec/MacroSystem", A2090A_CM) -END - -BEGIN_PROD(KCS) - PROD("KCS Power PC Board", POWER_BOARD) -END - -BEGIN_PROD(CARDCO) - PROD("Kronos 2000 SCSI Controller", KRONOS_2000_SCSI) - PROD("A1000 SCSI Controller", A1000_SCSI) - PROD("Escort SCSI Controller", ESCORT_SCSI) - PROD("Cardco A2410 Hires Graphics card", CC_A2410) +BEGIN_PROD(CARDCO_1) + PROD("Kronos 2000", SCSI, CARDCO_KRONOS_2000_1) + PROD("A1000", SCSI, CARDCO_A1000_1) + PROD("Escort", SCSI, CARDCO_ESCORT) + PROD("A2410 HiRes", GFX, CARDCO_A2410) END BEGIN_PROD(A_SQUARED) - PROD("Live! 2000", LIVE_2000) + PROD("Live! 2000", VIDEO, A_SQUARED_LIVE_2000) END -BEGIN_PROD(COMSPEC) - PROD("AX2000", AX2000) +BEGIN_PROD(COMSPEC_COMMUNICATIONS) + PROD("AX2000", RAM, COMSPEC_COMMUNICATIONS_AX2000) END -BEGIN_PROD(ANAKIN) - PROD("Easyl Tablet", EASYL) +BEGIN_PROD(ANAKIN_RESEARCH) + PROD("Easyl", TABLET, ANAKIN_RESEARCH_EASYL) END BEGIN_PROD(MICROBOTICS) - PROD("StarBoard II", STARBOARD_II) - PROD("StarDrive", STARDRIVE) - PROD("8-Up (Rev A)", 8_UP_A) - PROD("8-Up (Rev Z)", 8_UP_Z) - PROD("Delta Card RAM", DELTA_RAM) - PROD("8-Star RAM", 8_STAR_RAM) - PROD("8-Star", 8_STAR) - PROD("VXL RAM", VXL_RAM) - PROD("VXL-30 Turbo Board", VXL_30) - PROD("Delta Card", DELTA) - PROD("MBX 1200", MBX_1200) - PROD("Hardframe 2000", HARDFRAME_2000) - PROD("MBX 1200", MBX_1200_2) + PROD("StarBoard II", RAM, MICROBOTICS_STARBOARD_II) + PROD("StarDrive", SCSI, MICROBOTICS_STARDRIVE) + PROD("8-Up (Rev A)", RAM, MICROBOTICS_8_UP_A) + PROD("8-Up (Rev Z)", RAM, MICROBOTICS_8_UP_Z) + PROD("Delta", RAM, MICROBOTICS_DELTA_RAM) + PROD("8-Star", RAM, MICROBOTICS_8_STAR_RAM) + PROD("8-Star", MISC, MICROBOTICS_8_STAR) + PROD("VXL RAM*32", RAM, MICROBOTICS_VXL_RAM_32) + PROD("VXL-30", TURBO, MICROBOTICS_VXL_68030) + PROD("Delta", MISC, MICROBOTICS_DELTA) + PROD("MBX 1200/1200z", RAM, MICROBOTICS_MBX_1200_1200Z_RAM) + PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_1) + PROD("Hardframe 2000", SCSI, MICROBOTICS_HARDFRAME_2000_2) + PROD("MBX 1200/1200z", MISC, MICROBOTICS_MBX_1200_1200Z) END -BEGIN_PROD(ACCESS) +BEGIN_PROD(ACCESS_ASSOCIATES_ALEGRA) END -BEGIN_PROD(EXPANSION_TECH) +BEGIN_PROD(EXPANSION_TECHNOLOGIES) END BEGIN_PROD(ASDG) - PROD("Memory Expansion", ASDG_MEMORY) - PROD("Memory Expansion", ASDG_MEMORY_2) - PROD("Lan Rover Ethernet", LAN_ROVER) - PROD("Twin-X Serial Card", TWIN_X) + PROD(NULL, RAM, ASDG_MEMORY_1) + PROD(NULL, RAM, ASDG_MEMORY_2) + PROD("EB-920 Lan Rover", ETHERNET, ASDG_EB920_LAN_ROVER) + PROD("GPIB/Dual IEEE-488/Twin-X", MULTIIO, ASDG_GPIB_DUALIEEE488_TWIN_X) END -BEGIN_PROD(IMTRONICS) - PROD("Hurricane 2800 68030", HURRICANE_2800) - PROD("Hurricane 2800 68030", HURRICANE_2800_2) +BEGIN_PROD(IMTRONICS_1) + PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_1) + PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_2) END -BEGIN_PROD(UNIV_OF_LOWELL) - PROD("A2410 Hires Graphics Card", A2410) +BEGIN_PROD(CBM_UNIVERSITY_OF_LOWELL) + PROD("A2410 HiRes", GFX, CBM_A2410) END BEGIN_PROD(AMERISTAR) - PROD("A2065 Ethernet Card", AMERISTAR2065) - PROD("A560 Arcnet Card", A560) - PROD("A4066 Ethernet Card", A4066) + PROD("A2065", ETHERNET, AMERISTAR_A2065) + PROD("A560", ARCNET, AMERISTAR_A560) + PROD("A4066", ETHERNET, AMERISTAR_A4066) END BEGIN_PROD(SUPRA) - PROD("SupraDrive 4x4 SCSI Controller", SUPRADRIVE_4x4) - PROD("2000 DMA HD", SUPRA_2000) - PROD("500 HD/RAM", SUPRA_500) - PROD("500XP/2000 RAM", SUPRA_500XP) - PROD("500RX/2000 RAM", SUPRA_500RX) - PROD("2400zi Modem", SUPRA_2400ZI) - PROD("Wordsync SCSI Controller", WORDSYNC) - PROD("Wordsync II SCSI Controller", WORDSYNC_II) - PROD("2400zi+ Modem", SUPRA_2400ZIPLUS) + PROD("SupraDrive 4x4", SCSI, SUPRA_SUPRADRIVE_4x4) + PROD("1000", RAM, SUPRA_1000_RAM) + PROD("2000 DMA", SCSI, SUPRA_2000_DMA) + PROD("500", SCSI_RAM, SUPRA_500) + PROD("500", SCSI, SUPRA_500_SCSI) + PROD("500XP/2000", RAM, SUPRA_500XP_2000_RAM) + PROD("500RX/2000", RAM, SUPRA_500RX_2000_RAM) + PROD("2400zi", MODEM, SUPRA_2400ZI) + PROD("500XP/SupraDrive WordSync", SCSI, SUPRA_500XP_SUPRADRIVE_WORDSYNC) + PROD("SupraDrive WordSync II", SCSI, SUPRA_SUPRADRIVE_WORDSYNC_II) + PROD("2400zi+", MODEM, SUPRA_2400ZIPLUS) END -BEGIN_PROD(CSA) - PROD("Magnum 40 SCSI Controller", MAGNUM) - PROD("12 Gauge SCSI Controller", 12GAUGE) +BEGIN_PROD(COMPUTER_SYSTEMS_ASSOCIATES) + PROD("Magnum 40", TURBO_SCSI, CSA_MAGNUM) + PROD("12 Gauge", SCSI, CSA_12_GAUGE) END -BEGIN_PROD(MTEC2) - PROD("AT500 RAM", AT500_2) +BEGIN_PROD(MARC_MICHAEL_GROTH) END -BEGIN_PROD(GVP3) - PROD("Impact SCSI/Memory", IMPACT) +BEGIN_PROD(M_TECH) + PROD("AT500", RAM, MTEC_AT500_1) +END + +BEGIN_PROD(GREAT_VALLEY_PRODUCTS_1) + PROD("Impact Series I", SCSI_RAM, GVP_IMPACT_SERIES_I) END BEGIN_PROD(BYTEBOX) - PROD("A500", BYTEBOX_A500) + PROD("A500", UNKNOWN, BYTEBOX_A500) END -BEGIN_PROD(POWER_COMPUTING) - PROD("DKB 3128 RAM", DKB_3128) - PROD("Rapid Fire SCSI Controller", RAPID_FIRE) - PROD("DKB 1202 RAM", DKB_1202) - PROD("DKB Cobra / Viper II Turbo Board", VIPER_II_COBRA) - PROD("WildFire 060 Turbo Board", WILDFIRE_060) - PROD("WildFire 060 Turbo Board", WILDFIRE_060_2) -END - -BEGIN_PROD(GVP) - PROD("Impact Series-I SCSI 4K", IMPACT_I_4K) - PROD("Impact Series-I SCSI 16K/2", IMPACT_I_16K_2) - PROD("Impact Series-I SCSI 16K/3", IMPACT_I_16K_3) - PROD("Impact 3001 IDE", IMPACT_3001_IDE) -/* PROD("Impact 3001 RAM", IMPACT_3001_RAM) */ - PROD("Generic GVP product", GVP) - PROD("Series II SCSI Controller", GVPIISCSI) - PROD("Series II SCSI Controller", GVPIISCSI_2) - PROD("Series II RAM", GVPIIRAM) - PROD("A2000 68030 Turbo Board", GVP_A2000_030) -/* PROD("Impact 3001 IDE", IMPACT_3001_IDE_2) */ - PROD("GFORCE 040 with SCSI Controller", GFORCE_040_SCSI) - PROD("IV-24 Graphics Board", GVPIV_24) - PROD("GFORCE 040 Turbo Board", GFORCE_040) -/* PROD("I/O Extender", GVPIO_EXT) */ -END - -BEGIN_GVP_PROD - GVP_PROD("GFORCE 040", GFORCE_040) - GVP_PROD("GFORCE 040 with SCSI controller", GFORCE_040_SCSI) - GVP_PROD("A1291 SCSI controller", A1291_SCSI) - GVP_PROD("COMBO 030 R4", COMBO_R4) - GVP_PROD("COMBO 030 R4 with SCSI controller", COMBO_R4_SCSI) - GVP_PROD("Phone Pak", PHONEPAK) - GVP_PROD("IO-Extender", IOEXT) - GVP_PROD("GFORCE 030", GFORCE_030) - GVP_PROD("GFORCE 030 with SCSI controller", GFORCE_030_SCSI) - GVP_PROD("A530", A530) - GVP_PROD("A530 with SCSI", A530_SCSI) - GVP_PROD("COMBO 030 R3", COMBO_R3) - GVP_PROD("COMBO 030 R3 with SCSI controller", COMBO_R3_SCSI) - GVP_PROD("SERIES-II SCSI controller", SERIESII) +BEGIN_PROD(DKB_POWER_COMPUTING) + PROD("SecureKey", UNKNOWN, DKB_POWER_COMPUTING_SECUREKEY) + PROD("DKM 3128", RAM, DKB_POWER_COMPUTING_DKM_3128) + PROD("Rapid Fire", SCSI, DKB_POWER_COMPUTING_RAPID_FIRE) + PROD("DKM 1202", FPU_RAM, DKB_POWER_COMPUTING_DKM_1202) + PROD("Cobra/Viper II 68EC030", TURBO, DKB_POWER_COMPUTING_COBRA_VIPER_II_68EC030) + PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_1) + PROD("WildFire 060", TURBO, DKB_POWER_COMPUTING_WILDFIRE_060_2) +END + +BEGIN_PROD(GREAT_VALLEY_PRODUCTS_2) + PROD("Impact Series I (4K)", SCSI, GVP_IMPACT_SERIES_I_4K) + PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_2) + PROD("Impact Series I (16K/2)", SCSI, GVP_IMPACT_SERIES_I_16K_3) + PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_1) + PROD("Impact 3001", RAM, GVP_IMPACT_3001_RAM) + PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_1) +/* PROD(NULL, UNKNOWN, GVP_EPC_BASE) */ + PROD("Impact 3001", IDE, GVP_IMPACT_3001_IDE_2) +/* PROD("A2000 030", TURBO, GVP_A2000_030) */ +/* PROD("GForce 040", TURBO_SCSI, GFORCE_040_SCSI_2) */ + PROD("GForce 040/060", TURBO_SCSI, GVP_GFORCE_040_060) + PROD("Impact Vision 24", GFX, GVP_IMPACT_VISION_24) + PROD("GForce 040", TURBO, GVP_GFORCE_040_2) +END + +BEGIN_GVP_PROD /* ZORRO_PROD_GVP_EPC_BASE */ + GVP_PROD("GForce 040", TURBO, GVP_GFORCE_040_1) + GVP_PROD("GForce 040", TURBO_SCSI, GVP_GFORCE_040_SCSI_1) + GVP_PROD("A1291", SCSI, GVP_A1291) + GVP_PROD("Combo 030 R4", TURBO, GVP_COMBO_030_R4) + GVP_PROD("Combo 030 R4", TURBO_SCSI, GVP_COMBO_030_R4_SCSI) + GVP_PROD("Phone Pak", UNKNOWN, GVP_PHONEPAK) + GVP_PROD("IO-Extender", MULTIIO, GVP_IO_EXTENDER) + GVP_PROD("GForce 030", TURBO, GVP_GFORCE_030) + GVP_PROD("GForce 030", TURBO_SCSI, GVP_GFORCE_030_SCSI) + GVP_PROD("A530", TURBO, GVP_A530) + GVP_PROD("A530", TURBO_SCSI, GVP_A530_SCSI) + GVP_PROD("Combo 030 R3", TURBO, GVP_COMBO_030_R3) + GVP_PROD("Combo 030 R3", TURBO_SCSI, GVP_COMBO_030_R3_SCSI) + GVP_PROD("Series-II", SCSI, GVP_SERIES_II) END -BEGIN_PROD(SYNERGY) +BEGIN_PROD(CALIFORNIA_ACCESS_SYNERGY) + PROD("Malibu", SCSI, CALIFORNIA_ACCESS_SYNERGY_MALIBU) END BEGIN_PROD(XETEC) - PROD("FastCard SCSI Controller", FASTCARD_SCSI) - PROD("FastCard RAM", FASTCARD_RAM) + PROD("FastCard", SCSI, XETEC_FASTCARD) + PROD("FastCard", RAM, XETEC_FASTCARD_RAM) + PROD("FastCard Plus", SCSI, XETEC_FASTCARD_PLUS) END -BEGIN_PROD(PPI) - PROD("Mercury Turbo Board", MERCURY) - PROD("PP&S A3000 68040 Turbo Board", PPS_A3000_040) - PROD("PP&S A2000 68040 Turbo Board", PPS_A2000_040) - PROD("Zeus SCSI Controller", ZEUS) - PROD("PP&S A500 68040 Turbo Board", PPS_A500_040) +BEGIN_PROD(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS) + PROD("Mercury", TURBO, PPS_MERCURY) + PROD("A3000 68040", TURBO, PPS_A3000_68040) + PROD("A2000 68040", TURBO, PPS_A2000_68040) + PROD("Zeus", TURBO_SCSI_RAM, PPS_ZEUS) + PROD("A500 68040", TURBO, PPS_A500_68040) END BEGIN_PROD(XEBEC) END -BEGIN_PROD(SPIRIT) - PROD("HDA 506 Harddisk", HDA_506) - PROD("OctaByte RAM", OCTABYTE_RAM) +BEGIN_PROD(SPIRIT_TECHNOLOGY) + PROD("Insider IN1000", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN1000) + PROD("Insider IN500", RAM, SPIRIT_TECHNOLOGY_INSIDER_IN500) + PROD("SIN500", RAM, SPIRIT_TECHNOLOGY_SIN500) + PROD("HDA 506", HD, SPIRIT_TECHNOLOGY_HDA_506) + PROD("AX-S", MISC, SPIRIT_TECHNOLOGY_AX_S) + PROD("OctaByte", RAM, SPIRIT_TECHNOLOGY_OCTABYTE) + PROD("Inmate", SCSI_RAM, SPIRIT_TECHNOLOGY_INMATE) +END + +BEGIN_PROD(SPIRIT_TECHNOLOGY_2) END -BEGIN_PROD(BSC) - PROD("ALF 3 SCSI Controller", ALF_3_SCSI) +BEGIN_PROD(BSC_ALFADATA_1) + PROD("ALF 3", SCSI, BSC_ALF_3_1) END -BEGIN_PROD(BSC3) - PROD("ALF 2 SCSI Controller", ALF_2_SCSI) - PROD("ALF 2 SCSI Controller", ALF_2_SCSI_2) - PROD("ALF 3 SCSI Controller", ALF_3_SCSI_2) +BEGIN_PROD(BSC_ALFADATA_2) + PROD("ALF 2", SCSI, BSC_ALF_2_1) + PROD("ALF 2", SCSI, BSC_ALF_2_2) + PROD("ALF 3", SCSI, BSC_ALF_3_2) END -BEGIN_PROD(C_LTD) - PROD("Kronos SCSI Controller", KRONOS_SCSI) - PROD("A1000 SCSI Controller", A1000_SCSI_2) +BEGIN_PROD(CARDCO_2) + PROD("Kronos", SCSI, CARDCO_KRONOS_2000_2) + PROD("A1000", SCSI, CARDCO_A1000_2) END BEGIN_PROD(JOCHHEIM) - PROD("Jochheim RAM", JOCHHEIM_RAM) + PROD(NULL, RAM, JOCHHEIM_RAM) END -BEGIN_PROD(CHECKPOINT) - PROD("Serial Solution", SERIAL_SOLUTION) +BEGIN_PROD(CHECKPOINT_TECHNOLOGIES) + PROD("Serial Solution", SERIAL, CHECKPOINT_TECHNOLOGIES_SERIAL_SOLUTION) +END + +BEGIN_PROD(EDOTRONIK) + PROD("IEEE-488 Interface Board", UNKNOWN, EDOTRONIK_IEEE_488) + PROD("CBM-8032 Board", UNKNOWN, EDOTRONIK_8032) + PROD(NULL, SERIAL, EDOTRONIK_MULTISERIAL) + PROD("24Bit Realtime Video Digitizer", UNKNOWN, EDOTRONIK_VIDEODIGITIZER) + PROD("32Bit Parallel I/O Interface", UNKNOWN, EDOTRONIK_PARALLEL_IO) + PROD("PIC Prototyping Board", UNKNOWN, EDOTRONIK_PIC_PROTOYPING) + PROD("16 Channel ADC Interface", UNKNOWN, EDOTRONIK_ADC) + PROD("VME-Bus Controller", UNKNOWN, EDOTRONIK_VME) + PROD("DSP96000 Realtime Data Acquisition", DSP, EDOTRONIK_DSP96000) +END + +BEGIN_PROD(NES_INC) + PROD(NULL, RAM, NES_INC_RAM) END BEGIN_PROD(ICD) - PROD("Advantage 2000 SCSI Controller", ADVANTAGE_2000) + PROD("Advantage 2000", SCSI, ICD_ADVANTAGE_2000_SCSI) + PROD("Advantage", IDE, ICD_ADVANTAGE_2000_SCSI) + PROD("Advantage 2080", RAM, ICD_ADVANTAGE_2080_RAM) +END + +BEGIN_PROD(KUPKE_2) + PROD("Omti", HD, KUPKE_OMTI) + PROD("Golem SCSI-II", SCSI, KUPKE_SCSI_II) + PROD("Golem Box", UNKNOWN, KUPKE_GOLEM_BOX) + PROD("030/882", TURBO, KUPKE_030_882) + PROD("Golem", SCSI, KUPKE_SCSI_AT) END -BEGIN_PROD(KUPKE2) - PROD("Golem SCSI-II Controller", KUPKE_SCSI_II) - PROD("Golem Box", GOLEM_BOX) - PROD("030/882 Turbo Board", KUPKE_TURBO) - PROD("Golem SCSI/AT Controller", KUPKE_SCSI_AT) +BEGIN_PROD(GREAT_VALLEY_PRODUCTS_3) + PROD("A2000-RAM8/2", MISC, GVP_A2000_RAM8) + PROD("Impact Series II", RAM, GVP_IMPACT_SERIES_II_RAM_2) END -BEGIN_PROD(GVP4) - PROD("A2000-RAM8/2", A2000_RAM8) +BEGIN_PROD(INTERWORKS_NETWORK) END -BEGIN_PROD(INTERWORKS_NET) +BEGIN_PROD(HARDITAL_SYNTHESIS) + PROD("TQM 68030+68882", TURBO, HARDITAL_SYNTHESIS_TQM_68030_68882) END -BEGIN_PROD(HARDITAL) - PROD("TQM 68030+68882 Turbo Board", TQM) +BEGIN_PROD(APPLIED_ENGINEERING) + PROD("DL2000", MODEM, APPLIED_ENGINEERING_DL2000) + PROD("RAM Works", RAM, APPLIED_ENGINEERING_RAM_WORKS) END -BEGIN_PROD(BSC2) - PROD("Oktagon 2008 SCSI Controller", OKTAGON_SCSI) - PROD("Tandem AT-2008/508 IDE Controller", TANDEM) - PROD("Alpha RAM 1200", ALPHA_RAM_1200) - PROD("Oktagon 2008 RAM", OKTAGON_RAM) - PROD("Alfa Data MultiFace I", MULTIFACE_I) - PROD("Alfa Data MultiFace II", MULTIFACE_II) - PROD("Alfa Data MultiFace III", MULTIFACE_III) - PROD("Framebuffer", BSC_FRAEMBUFFER) - PROD("Graffiti Graphics Board (RAM)", GRAFFITI_RAM) - PROD("Graffiti Graphics Board (REG)", GRAFFITI_REG) - PROD("ISDN MasterCard", ISDN_MASTERCARD) - PROD("ISDN MasterCard II", ISDN_MASTERCARD_2) +BEGIN_PROD(BSC_ALFADATA_3) + PROD("Oktagon 2008", SCSI, BSC_OKTAGON_2008) + PROD("Tandem AT-2008/508", IDE, BSC_TANDEM_AT_2008_508) + PROD("Alpha RAM 1200", RAM, BSC_ALFA_RAM_1200) + PROD("Oktagon 2008", RAM, BSC_OKTAGON_2008_RAM) + PROD("MultiFace I", MULTIIO, BSC_MULTIFACE_I) + PROD("MultiFace II", MULTIIO, BSC_MULTIFACE_II) + PROD("MultiFace III", MULTIIO, BSC_MULTIFACE_III) + PROD("Framebuffer", MISC, BSC_FRAMEBUFFER) + PROD("Graffiti", GFXRAM, BSC_GRAFFITI_RAM) + PROD("Graffiti", GFX, BSC_GRAFFITI_REG) + PROD("ISDN MasterCard", ISDN, BSC_ISDN_MASTERCARD) + PROD("ISDN MasterCard II", ISDN, BSC_ISDN_MASTERCARD_II) END -BEGIN_PROD(ADV_SYS_SOFT) - PROD("Nexus SCSI Controller", NEXUS_SCSI) - PROD("Nexus RAM", NEXUS_RAM) +BEGIN_PROD(PHOENIX) + PROD("ST506", HD, PHOENIX_ST506) + PROD(NULL, SCSI, PHOENIX_SCSI) + PROD(NULL, RAM, PHOENIX_RAM) +END + +BEGIN_PROD(ADVANCED_STORAGE_SYSTEMS) + PROD("Nexus", SCSI, ADVANCED_STORAGE_SYSTEMS_NEXUS) + PROD("Nexus", RAM, ADVANCED_STORAGE_SYSTEMS_NEXUS_RAM) END BEGIN_PROD(IMPULSE) - PROD("FireCracker 24", FIRECRACKER_24) + PROD("FireCracker 24", GFX, IMPULSE_FIRECRACKER_24) END BEGIN_PROD(IVS) - PROD("GrandSlam PIC 2 RAM", GRANDSLAM_PIC_2) - PROD("GrandSlam PIC 1 RAM", GRANDSLAM_PIC_1) - PROD("OverDrive HD", IVS_OVERDRIVE) - PROD("Trumpcard Classic SCSI Controller", TRUMPCARD_CLASSIC) - PROD("Trumpcard Pro SCSI Controller", TRUMPCARD_PRO) - PROD("Meta-4 RAM", META_4) - PROD("Wavetools Sound Board", WAVETOOLS) - PROD("Vector SCSI Controller", VECTOR) - PROD("Vector SCSI Controller", VECTOR_2) + PROD("GrandSlam PIC 2", RAM, IVS_GRANDSLAM_PIC_2) + PROD("GrandSlam PIC 1", RAM, IVS_GRANDSLAM_PIC_1) + PROD("OverDrive", HD, IVS_OVERDRIVE) + PROD("TrumpCard Classic", SCSI, IVS_TRUMPCARD_CLASSIC) + PROD("TrumpCard Pro/GrandSlam", SCSI, IVS_TRUMPCARD_PRO_GRANDSLAM) + PROD("Meta-4", RAM, IVS_META_4) + PROD("Wavetools", AUDIO, IVS_WAVETOOLS) + PROD("Vector", SCSI, IVS_VECTOR_1) + PROD("Vector", SCSI, IVS_VECTOR_2) END -BEGIN_PROD(VECTOR) - PROD("Connection Serial IO", CONNECTION) +BEGIN_PROD(VECTOR_1) + PROD("Connection", MULTIIO, VECTOR_CONNECTION_1) END BEGIN_PROD(XPERT_PRODEV) - PROD("Visiona Graphics Board (RAM)", VISIONA_RAM) - PROD("Visiona Graphics Board (REG)", VISIONA_REG) - PROD("Merlin Graphics Board (RAM)", MERLIN_RAM) - PROD("Merlin Graphics Board (REG)", MERLIN_REG) - PROD("Merlin Graphics Board (REG)", MERLIN_REG_2) + PROD("Visiona", GFXRAM, XPERT_PRODEV_VISIONA_RAM) + PROD("Visiona", GFX, XPERT_PRODEV_VISIONA_REG) + PROD("Merlin", GFXRAM, XPERT_PRODEV_MERLIN_RAM) + PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_1) + PROD("Merlin", GFX, XPERT_PRODEV_MERLIN_REG_2) END BEGIN_PROD(HYDRA_SYSTEMS) - PROD("Amiganet Board", AMIGANET) + PROD("Amiganet", ETHERNET, HYDRA_SYSTEMS_AMIGANET) END -BEGIN_PROD(SUNRIZE) - PROD("AD516 Audio", AD516) +BEGIN_PROD(SUNRIZE_INDUSTRIES) + PROD("AD1012", AUDIO, SUNRIZE_INDUSTRIES_AD1012) + PROD("AD516", AUDIO, SUNRIZE_INDUSTRIES_AD516) + PROD("DD512", AUDIO, SUNRIZE_INDUSTRIES_DD512) END BEGIN_PROD(TRICERATOPS) - PROD("Multi I/O Board", TRICERATOPS) + PROD(NULL, MULTIIO, TRICERATOPS_MULTI_IO) END BEGIN_PROD(APPLIED_MAGIC) - PROD("DMI Resolver Graphics Board", DMI_RESOLVER) - PROD("Digital Broadcaster", DIGITAL_BCASTER) + PROD("DMI Resolver", GFX, APPLIED_MAGIC_DMI_RESOLVER) + PROD("Digital Broadcaster", VIDEO, APPLIED_MAGIC_DIGITAL_BROADCASTER) END BEGIN_PROD(GFX_BASE) - PROD("GDA-1 Graphics Board (RAM)", GDA_1_RAM) - PROD("GDA-1 Graphics Board (REG)", GDA_1_REG) + PROD("GDA-1 VRAM", GFX, GFX_BASE_GDA_1_VRAM) + PROD("GDA-1", GFX, GFX_BASE_GDA_1) END BEGIN_PROD(ROCTEC) - PROD("RH 800C Hard Disk Controller", RH_800C) - PROD("RH 800C RAM", RH_800C_RAM) + PROD("RH 800C", HD, ROCTEC_RH_800C) + PROD("RH 800C", RAM, ROCTEC_RH_800C_RAM) +END + +BEGIN_PROD(KATO) + PROD("Melody MPEG", AUDIO, KATO_MELODY) + PROD("Rainbow II", GFX, HELFRICH_RAINBOW_II) /* ID clash!! */ + PROD("Rainbow III", GFX, HELFRICH_RAINBOW_III) /* ID clash!! */ +END + +BEGIN_PROD(ATLANTIS) END -BEGIN_PROD(HELFRICH1) - PROD("Rainbow3 Graphics Board", RAINBOW3) +BEGIN_PROD(PROTAR) END -BEGIN_PROD(SW_RESULT_ENTS) - PROD("GG2+ Bus Converter", GG2PLUS) +BEGIN_PROD(ACS) +END + +BEGIN_PROD(SOFTWARE_RESULTS_ENTERPRISES) + PROD("Golden Gate 2 Bus+", BRIDGE, SOFTWARE_RESULTS_ENTERPRISES_GOLDEN_GATE_2_BUS_PLUS) END BEGIN_PROD(MASOBOSHI) - PROD("Master Card RAM", MASTER_CARD_RAM) - PROD("Master Card SCSI Controller", MASTER_CARD_SCSI) - PROD("MVD 819", MVD_819) + PROD("MasterCard SC201", RAM, MASOBOSHI_MASTER_CARD_SC201) + PROD("MasterCard MC702", SCSI_IDE, MASOBOSHI_MASTER_CARD_MC702) + PROD("MVD 819", UNKNOWN, MASOBOSHI_MVD_819) END -BEGIN_PROD(VILLAGE_TRONIC) - PROD("Domino Graphics Board (RAM)", DOMINO_RAM) - PROD("Domino Graphics Board (REG)", DOMINO_REG) - PROD("Picasso II Graphics Board (RAM)", PICASSO_II_RAM) - PROD("Picasso II Graphics Board (REG)", PICASSO_II_REG) - PROD("Picasso II/II+ Graphics Board (Segmented Mode)", PICASSO_II_SEGM) - PROD("Picassio IV Graphics Board", PICASSO_IV) - PROD("Picassio IV Graphics Board", PICASSO_IV_2) - PROD("Picassio IV Graphics Board", PICASSO_IV_3) - PROD("Picassio IV Graphics Board", PICASSO_IV_4) - PROD("Ariadne Ethernet Card", ARIADNE) +BEGIN_PROD(MAINHATTAN_DATA) + PROD(NULL, IDE, MAINHATTAN_DATA_IDE) END -BEGIN_PROD(UTILITIES_ULTD) - PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE) - PROD("Emplant Deluxe SCSI Controller", EMPLANT_DELUXE2) +BEGIN_PROD(VILLAGE_TRONIC) + PROD("Domino", GFXRAM, VILLAGE_TRONIC_DOMINO_RAM) + PROD("Domino", GFX, VILLAGE_TRONIC_DOMINO_REG) + PROD("Domino 16M Prototype", GFX, VILLAGE_TRONIC_DOMINO_16M_PROTOTYPE) + PROD("Picasso II/II+", GFXRAM, VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM) + PROD("Picasso II/II+", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG) + PROD("Picasso II/II+ (Segmented Mode)", GFX, VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE) + PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM1) + PROD("Picasso IV Z2", GFXRAM, VILLAGE_TRONIC_PICASSO_IV_Z2_MEM2) + PROD("Picasso IV Z2", GFX, VILLAGE_TRONIC_PICASSO_IV_Z2_REG) + PROD("Picasso IV Z3", GFX, VILLAGE_TRONIC_PICASSO_IV_Z3) + PROD("Ariadne", ETHERNET_PARALLEL, VILLAGE_TRONIC_ARIADNE) +END + +BEGIN_PROD(UTILITIES_UNLIMITED) + PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE) + PROD("Emplant Deluxe", MACEMU, UTILITIES_UNLIMITED_EMPLANT_DELUXE2) END BEGIN_PROD(AMITRIX) - PROD("Multi-IO", AMITRIX_MULTI_IO) - PROD("CD-RAM Memory", AMITRIX_CD_RAM) + PROD(NULL, MULTIIO, AMITRIX_MULTI_IO) + PROD("CD-RAM", RAM, AMITRIX_CD_RAM) END BEGIN_PROD(ARMAX) - PROD("OmniBus Graphics Board", OMNIBUS) + PROD("OmniBus", GFX, ARMAX_OMNIBUS) END BEGIN_PROD(NEWTEK) - PROD("VideoToaster", VIDEOTOASTER) + PROD("VideoToaster", VIDEO, NEWTEK_VIDEOTOASTER) END -BEGIN_PROD(MTEC) - PROD("AT500 IDE Controller", AT500) - PROD("68030 Turbo Board", MTEC_68030) - PROD("68020i Turbo Board", MTEC_68020I) - PROD("A1200 T68030/42 RTC Turbo Board", MTEC_T1230) - PROD("8MB RAM", MTEC_RAM) +BEGIN_PROD(M_TECH_GERMANY) + PROD("AT500", IDE, MTEC_AT500_2) + PROD("68030", TURBO, MTEC_68030) + PROD("68020i", TURBO, MTEC_68020I) + PROD("A1200 T68030 RTC", TURBO, MTEC_A1200_T68030_RTC) + PROD("Viper Mk V/E-Matrix 530", TURBO_RAM, MTEC_VIPER_MK_V_E_MATRIX_530) + PROD("8MB", RAM, MTEC_8_MB_RAM) + PROD("Viper Mk V/E-Matrix 530 SCSI/IDE", SCSI_IDE, MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE) END -BEGIN_PROD(GVP2) - PROD("EGS 28/24 Spectrum Graphics Board (RAM)", SPECTRUM_RAM) - PROD("EGS 28/24 Spectrum Graphics Board (REG)", SPECTRUM_REG) +BEGIN_PROD(GREAT_VALLEY_PRODUCTS_4) + PROD("EGS 28/24 Spectrum", GFX, GVP_EGS_28_24_SPECTRUM_REG) + PROD("EGS 28/24 Spectrum", GFXRAM, GVP_EGS_28_24_SPECTRUM_RAM) END -BEGIN_PROD(HELFRICH2) - PROD("Piccolo Graphics Board (RAM)", PICCOLO_RAM) - PROD("Piccolo Graphics Board (REG)", PICCOLO_REG) - PROD("PeggyPlus MPEG Decoder Board", PEGGY_PLUS) - PROD("VideoCruncher", VIDEOCRUNCHER) - PROD("SD64 Graphics Board (RAM)", SD64_RAM) - PROD("SD64 Graphics Board (REG)", SD64_REG) +BEGIN_PROD(APOLLO_1) + PROD("A1200", FPU_RAM, APOLLO_A1200) END -BEGIN_PROD(MACROSYSTEMS) - PROD("Warp Engine 40xx SCSI Controller", WARP_ENGINE) +BEGIN_PROD(HELFRICH_2) + PROD("Piccolo", GFXRAM, HELFRICH_PICCOLO_RAM) + PROD("Piccolo", GFX, HELFRICH_PICCOLO_REG) + PROD("PeggyPlus MPEG", VIDEO, HELFRICH_PEGGY_PLUS_MPEG) + PROD("VideoCruncher", VIDEO, HELFRICH_VIDEOCRUNCHER) + PROD("Piccolo SD64", GFXRAM, HELFRICH_SD64_RAM) + PROD("Piccolo SD64", GFX, HELFRICH_SD64_REG) END -BEGIN_PROD(ELBOX) - PROD("Elbox 1200/4 RAM", ELBOX_1200) +BEGIN_PROD(MACROSYSTEMS_USA) + PROD("Warp Engine 40xx", TURBO_SCSI_RAM, MACROSYSTEMS_WARP_ENGINE_40xx) END -BEGIN_PROD(HARMS_PROF) - PROD("030 plus", HARMS_030_PLUS) - PROD("3500 Turbo board", 3500_TURBO) +BEGIN_PROD(ELBOX_COMPUTER) + PROD("1200/4", RAM, ELBOX_COMPUTER_1200_4) +END + +BEGIN_PROD(HARMS_PROFESSIONAL) + PROD("030 Plus", TURBO, HARMS_PROFESSIONAL_030_PLUS) + PROD("3500 Professional", TURBO_RAM, HARMS_PROFESSIONAL_3500) END BEGIN_PROD(MICRONIK) - PROD("RCA 120 RAM", RCA_120) + PROD("RCA 120", RAM, MICRONIK_RCA_120) +END + +BEGIN_PROD(MICRONIK2) + PROD("Z3i A1200 Zorro III + SCSI", SCSI, MICRONIK2_Z3I) END -BEGIN_PROD(MEGA_MICRO) - PROD("SCRAM 500 SCSI Controller", SCRAM_500_SCSI) - PROD("SCRAM 500 RAM", SCRAM_500_RAM) +BEGIN_PROD(MEGAMICRO) + PROD("SCRAM 500", SCSI, MEGAMICRO_SCRAM_500) + PROD("SCRAM 500", RAM, MEGAMICRO_SCRAM_500_RAM) END -BEGIN_PROD(IMTRONICS2) - PROD("Hurricane 2800 68030", HURRICANE_2800_3) - PROD("Hurricane 2800 68030", HURRICANE_2800_4) +BEGIN_PROD(IMTRONICS_2) + PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_3) + PROD("Hurricane 2800", TURBO_RAM, IMTRONICS_HURRICANE_2800_4) END -BEGIN_PROD(KUPKE3) - PROD("Golem HD 3000", GOLEM_3000) +BEGIN_PROD(INDIVIDUAL_COMPUTERS) + PROD("Buddha", IDE, INDIVIDUAL_COMPUTERS_BUDDHA) + PROD("Catweasel", IDE_FLOPPY, INDIVIDUAL_COMPUTERS_CATWEASEL) +END + +BEGIN_PROD(KUPKE_3) + PROD("Golem HD 3000", HD, KUPKE_GOLEM_HD_3000) END BEGIN_PROD(ITH) - PROD("ISDN-Master II", ISDN_MASTER_II) + PROD("ISDN-Master II", ISDN, ITH_ISDN_MASTER_II) END BEGIN_PROD(VMC) - PROD("ISDN Blaster Z2", ISDN_BLASTER_Z2) - PROD("HyperCom 4", HYPERCOM_4) + PROD("ISDN Blaster Z2", ISDN, VMC_ISDN_BLASTER_Z2) + PROD("HyperCom 4", MULTIIO, VMC_HYPERCOM_4) END BEGIN_PROD(INFORMATION) - PROD("ISDN Engine I", ISDN_ENGINE_I) + PROD("ISDN Engine I", ISDN, INFORMATION_ISDN_ENGINE_I) END BEGIN_PROD(VORTEX) - PROD("Golden Gate 80386SX Board", GOLDEN_GATE_386SX) - PROD("Golden Gate RAM", GOLDEN_GATE_RAM) - PROD("Golden Gate 80486 Board", GOLDEN_GATE_486) + PROD("Golden Gate 80386SX", BRIDGE, VORTEX_GOLDEN_GATE_80386SX) + PROD("Golden Gate", RAM, VORTEX_GOLDEN_GATE_RAM) + PROD("Golden Gate 80486", BRIDGE, VORTEX_GOLDEN_GATE_80486) END -BEGIN_PROD(DATAFLYER) - PROD("4000SX SCSI Controller", DATAFLYER_4000SXS) - PROD("4000SX RAM", DATAFLYER_4000SXR) +BEGIN_PROD(EXPANSION_SYSTEMS) + PROD("DataFlyer 4000SX", SCSI, EXPANSION_SYSTEMS_DATAFLYER_4000SX) + PROD("DataFlyer 4000SX", RAM, EXPANSION_SYSTEMS_DATAFLYER_4000SX_RAM) END BEGIN_PROD(READYSOFT) - PROD("AMax II/IV", AMAX) + PROD("AMax II/IV", MACEMU, READYSOFT_AMAX_II_IV) END BEGIN_PROD(PHASE5) - PROD("Blizzard RAM", BLIZZARD_RAM) - PROD("Blizzard", BLIZZARD) - PROD("Blizzard 1220-IV Turbo Board", BLIZZARD_1220_IV) - PROD("FastLane RAM", FASTLANE_RAM) - PROD("FastLane/Blizzard 1230-II/CyberSCSI", FASTLANE_SCSI) - PROD("Blizzard 1220/CyberStorm", CYBERSTORM_SCSI) - PROD("Blizzard 1230-III Turbo Board", BLIZZARD_1230_III) - PROD("Blizzard 1230-IV/1260 Turbo Board", BLIZZARD_1230_IV) - PROD("Blizzard 2060 SCSI Controller", BLIZZARD_2060SCSI) - PROD("CyberStorm Mk II", CYBERSTORM_II) - PROD("CyberVision64 Graphics Board", CYBERVISION) - PROD("CyberVision64-3D Graphics Board Prototype)", CYBERVISION3D_PRT) - PROD("CyberVision64-3D Graphics Board", CYBERVISION3D) + PROD("Blizzard", RAM, PHASE5_BLIZZARD_RAM) + PROD("Blizzard", TURBO, PHASE5_BLIZZARD) + PROD("Blizzard 1220-IV", TURBO, PHASE5_BLIZZARD_1220_IV) + PROD("FastLane Z3", RAM, PHASE5_FASTLANE_Z3_RAM) + PROD("Blizzard 1230-II/Fastlane Z3/CyberSCSI/CyberStorm060", TURBO_SCSI, PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) + PROD("Blizzard 1220/CyberStorm", TURBO_SCSI, PHASE5_BLIZZARD_1220_CYBERSTORM) + PROD("Blizzard 1230", TURBO, PHASE5_BLIZZARD_1230) + PROD("Blizzard 1230-IV/1260", TURBO, PHASE5_BLIZZARD_1230_IV_1260) + PROD("Blizzard 2060", TURBO, PHASE5_BLIZZARD_2060) + PROD("CyberStorm Mk II", FLASHROM, PHASE5_CYBERSTORM_MK_II) + PROD("CyberVision64", GFX, PHASE5_CYBERVISION64) + PROD("CyberVision64-3D Prototype", GFX, PHASE5_CYBERVISION64_3D_PROTOTYPE) + PROD("CyberVision64-3D", GFX, PHASE5_CYBERVISION64_3D) + PROD("CyberStorm Mk III", TURBO_SCSI, PHASE5_CYBERSTORM_MK_III) END BEGIN_PROD(DPS) - PROD("Personal Animation Recorder", DPS_PAR) + PROD("Personal Animation Recorder", VIDEO, DPS_PERSONAL_ANIMATION_RECORDER) END -BEGIN_PROD(APOLLO2) - PROD("A620 68020 Accelerator", A620) - PROD("A620 68020 Accelerator", A620_2) +BEGIN_PROD(APOLLO_2) + PROD("A620 68020", TURBO, APOLLO_A620_68020_1) + PROD("A620 68020", TURBO, APOLLO_A620_68020_2) END -BEGIN_PROD(APOLLO) - PROD("AT-Apollo", AT_APOLLO) - PROD("Turbo Board", APOLLO_TURBO) +BEGIN_PROD(APOLLO_3) + PROD("AT-Apollo", UNKNOWN, APOLLO_AT_APOLLO) + PROD("1230/1240/1260/2030/4040/4060", TURBO, APOLLO_1230_1240_1260_2030_4040_4060) END -BEGIN_PROD(PETSOFF) - PROD("Delfina DSP", DELFINA) +BEGIN_PROD(PETSOFF_LP) + PROD("Delfina", DSP, PETSOFF_LP_DELFINA) END BEGIN_PROD(UWE_GERLACH) - PROD("RAM/ROM", UG_RAM_ROM) + PROD("RAM/ROM", MISC, UWE_GERLACH_RAM_ROM) END -BEGIN_PROD(MACROSYSTEMS2) - PROD("Maestro", MAESTRO) - PROD("VLab", VLAB) - PROD("Maestro Pro", MAESTRO_PRO) - PROD("Retina Z2 Graphics Board", RETINA_Z2) - PROD("MultiEvolution", MULTI_EVOLUTION) - PROD("Toccata Sound Board", TOCCATA) - PROD("Retina Z3 Graphics Board", RETINA_Z3) - PROD("VLab Motion", VLAB_MOTION) - PROD("Altais Graphics Board", ALTAIS) - PROD("Falcon '040 Turbo Board", FALCON_040) +BEGIN_PROD(MACROSYSTEMS_GERMANY) + PROD("Maestro", AUDIO, MACROSYSTEMS_MAESTRO) + PROD("VLab", VIDEO, MACROSYSTEMS_VLAB) + PROD("Maestro Pro", AUDIO, MACROSYSTEMS_MAESTRO_PRO) + PROD("Retina", GFX, MACROSYSTEMS_RETINA) + PROD("MultiEvolution", SCSI, MACROSYSTEMS_MULTI_EVOLUTION) + PROD("Toccata", AUDIO, MACROSYSTEMS_TOCCATA) + PROD("Retina Z3", GFX, MACROSYSTEMS_RETINA_Z3) + PROD("VLab Motion", VIDEO, MACROSYSTEMS_VLAB_MOTION) + PROD("Altais", GFX, MACROSYSTEMS_ALTAIS) + PROD("Falcon '040", TURBO, MACROSYSTEMS_FALCON_040) END BEGIN_PROD(COMBITEC) END -BEGIN_PROD(SKI) - PROD("MAST Fireball SCSI Controller", MAST_FIREBALL) - PROD("SCSI / Dual Serial", SKI_SCSI_SERIAL) +BEGIN_PROD(SKI_PERIPHERALS) + PROD("MAST Fireball", SCSI, SKI_PERIPHERALS_MAST_FIREBALL) + PROD("SCSI/Dual Serial", SCSI_SERIAL, SKI_PERIPHERALS_SCSI_DUAL_SERIAL) +END + +BEGIN_PROD(REIS_WARE_2) + PROD("Scan King", SCANNER, REIS_WARE_SCAN_KING) END BEGIN_PROD(CAMERON) - PROD("Personal A4", PERSONAL_A4) + PROD("Personal A4", SCANNER, CAMERON_PERSONAL_A4) END BEGIN_PROD(REIS_WARE) - PROD("Handyscanner", RW_HANDYSCANNER) + PROD("Handyscanner", SCANNER, REIS_WARE_HANDYSCANNER) END +BEGIN_PROD(PHOENIX_2) + PROD("ST506", HD, PHOENIX_ST506_2) + PROD(NULL, SCSI, PHOENIX_SCSI_2) + PROD(NULL, RAM, PHOENIX_RAM_2) +END -BEGIN_MANUF - MANUF("Pacific Peripherals", PACIFIC) - MANUF("Kupke", KUPKE) - MANUF("Memphis", MEMPHIS) - MANUF("3-State", 3_STATE) - MANUF("Commodore", COMMODORE2) - MANUF("Commodore", COMMODORE) - MANUF("Commodore", COMMODORE3) - MANUF("Kolff Computer Supplies", KCS) - MANUF("Cardco", CARDCO) - MANUF("A-Squared", A_SQUARED) - MANUF("ComSpec Communications", COMSPEC) - MANUF("Anakin", ANAKIN) - MANUF("MicroBotics", MICROBOTICS) - MANUF("Access Associates", ACCESS) - MANUF("Expansion Technologies", EXPANSION_TECH) - MANUF("ASDG", ASDG) - MANUF("Imtronics", IMTRONICS) - MANUF("University of Lowell", UNIV_OF_LOWELL) - MANUF("Ameristar", AMERISTAR) - MANUF("Supra", SUPRA) - MANUF("Computer Systems Ass.", CSA) - MANUF("M-Tech", MTEC2) - MANUF("Great Valley Products", GVP3) - MANUF("ByteBox", BYTEBOX) - MANUF("Power Computing", POWER_COMPUTING) - MANUF("Great Valley Products", GVP) - MANUF("Synergy", SYNERGY) - MANUF("Xetec", XETEC) - MANUF("Progressive Peripherals", PPI) - MANUF("Xebec", XEBEC) - MANUF("Spirit", SPIRIT) - MANUF("BSC", BSC) - MANUF("BSC", BSC3) - MANUF("C Ltd.", C_LTD) - MANUF("Jochheim", JOCHHEIM) - MANUF("Checkpoint Technologies", CHECKPOINT) - MANUF("ICD", ICD) - MANUF("Kupke", KUPKE2) - MANUF("Great Valley Products", GVP4) - MANUF("Interworks Network", INTERWORKS_NET) - MANUF("Hardital Synthesis", HARDITAL) - MANUF("BSC", BSC2) - MANUF("Advanced Systems & Software", ADV_SYS_SOFT) - MANUF("Impulse", IMPULSE) - MANUF("IVS", IVS) - MANUF("Vector", VECTOR) - MANUF("XPert/ProDev", XPERT_PRODEV) - MANUF("Hydra Systems", HYDRA_SYSTEMS) - MANUF("Sunrize Industries", SUNRIZE) - MANUF("Triceratops", TRICERATOPS) - MANUF("Applied Magic", APPLIED_MAGIC) - MANUF("GFX-Base", GFX_BASE) - MANUF("RocTec", ROCTEC) - MANUF("Helfrich", HELFRICH1) - MANUF("Software Result Enterprises", SW_RESULT_ENTS) - MANUF("Masoboshi", MASOBOSHI) - MANUF("Village Tronic", VILLAGE_TRONIC) - MANUF("Utilities Unlimited", UTILITIES_ULTD) - MANUF("Amitrix", AMITRIX) - MANUF("ArMax", ARMAX) - MANUF("NewTek", NEWTEK) - MANUF("M-Tech", MTEC) - MANUF("Great Valley Products", GVP2) - MANUF("Helfrich", HELFRICH2) - MANUF("MacroSystems", MACROSYSTEMS) - MANUF("ElBox Computer", ELBOX) - MANUF("Harms Professional", HARMS_PROF) - MANUF("Micronik", MICRONIK) - MANUF("MegaMicro", MEGA_MICRO) - MANUF("Imtronics", IMTRONICS2) - MANUF("Kupke", KUPKE3) - MANUF("ITH", ITH) - MANUF("VMC", VMC) - MANUF("Information", INFORMATION) - MANUF("Vortex", VORTEX) - MANUF("DataFlyer", DATAFLYER) - MANUF("ReadySoft", READYSOFT) - MANUF("Phase5", PHASE5) - MANUF("DPS", DPS) - MANUF("Apollo", APOLLO2) - MANUF("Apollo", APOLLO) - MANUF("Petsoff LP", PETSOFF) - MANUF("Uwe Gerlach", UWE_GERLACH) - MANUF("MacroSystems", MACROSYSTEMS2) - MANUF("Combitec", COMBITEC) - MANUF("SKI Peripherals", SKI) - MANUF("Cameron", CAMERON) - MANUF("Reis-Ware", REIS_WARE) +BEGIN_PROD(COMBITEC_2) + PROD(NULL, HD, COMBITEC_HD) + PROD("SRAM", RAM, COMBITEC_SRAM) END -#define NUM_MANUF (sizeof(Manufacturers)/sizeof(struct Manufacturer)) -#define NUM_GVP_PROD (sizeof(Ext_Prod_GVP)/sizeof(struct GVP_Product)) +BEGIN_PROD(HACKER) /* Unused */ +END + + +BEGIN_MANUF + MANUF("Pacific Peripherals", PACIFIC_PERIPHERALS) + MANUF("MacroSystems USA", MACROSYSTEMS_USA_2) + MANUF("Kupke", KUPKE_1) + MANUF("Memphis", MEMPHIS) + MANUF("3-State", 3_STATE) + MANUF("Commodore Braunschweig", COMMODORE_BRAUNSCHWEIG) + MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_1) + MANUF("Commodore West Chester", COMMODORE_WEST_CHESTER_2) + MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2) + MANUF("Kolff Computer Supplies", KOLFF_COMPUTER_SUPPLIES) + MANUF("Cardco Ltd.", CARDCO_1) + MANUF("A-Squared", A_SQUARED) + MANUF("Comspec Communications", COMSPEC_COMMUNICATIONS) + MANUF("Anakin Research", ANAKIN_RESEARCH) + MANUF("Microbotics", MICROBOTICS) + MANUF("Access Associates Alegra", ACCESS_ASSOCIATES_ALEGRA) + MANUF("Expansion Technologies (Pacific Cypress)", EXPANSION_TECHNOLOGIES) + MANUF("ASDG", ASDG) + MANUF("Ronin/Imtronics", IMTRONICS_1) + MANUF("Commodore/University of Lowell", CBM_UNIVERSITY_OF_LOWELL) + MANUF("Ameristar", AMERISTAR) + MANUF("Supra", SUPRA) + MANUF("Computer Systems Assosiates", COMPUTER_SYSTEMS_ASSOCIATES) + MANUF("Marc Michael Groth", MARC_MICHAEL_GROTH) + MANUF("M-Tech", M_TECH) + MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_1) + MANUF("ByteBox", BYTEBOX) + MANUF("DKB/Power Computing", DKB_POWER_COMPUTING) + MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_2) + MANUF("California Access (Synergy)", CALIFORNIA_ACCESS_SYNERGY) + MANUF("Xetec", XETEC) + MANUF("Progressive Peripherals & Systems", PROGRESSIVE_PERIPHERALS_AND_SYSTEMS) + MANUF("Xebec", XEBEC) + MANUF("Spirit Technology", SPIRIT_TECHNOLOGY) + MANUF("Spirit Technology", SPIRIT_TECHNOLOGY_2) + MANUF("BSC/Alfadata", BSC_ALFADATA_1) + MANUF("BSC/Alfadata", BSC_ALFADATA_2) + MANUF("Cardco Ltd.", CARDCO_2) + MANUF("Jochheim", JOCHHEIM) + MANUF("Checkpoint Technologies", CHECKPOINT_TECHNOLOGIES) + MANUF("Edotronik", EDOTRONIK) + MANUF("NES Inc.", NES_INC) + MANUF("ICD", ICD) + MANUF("Kupke", KUPKE_2) + MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_3) + MANUF("Interworks Network", INTERWORKS_NETWORK) + MANUF("Hardital Synthesis", HARDITAL_SYNTHESIS) + MANUF("Applied Engineering", APPLIED_ENGINEERING) + MANUF("BSC/Alfadata", BSC_ALFADATA_3) + MANUF("Phoenix", PHOENIX) + MANUF("Advanced Storage Systems", ADVANCED_STORAGE_SYSTEMS) + MANUF("Impulse", IMPULSE) + MANUF("IVS", IVS) + MANUF("Vector", VECTOR_1) + MANUF("XPert ProDev", XPERT_PRODEV) + MANUF("Hydra Systems", HYDRA_SYSTEMS) + MANUF("Sunrize Industries", SUNRIZE_INDUSTRIES) + MANUF("Triceratops", TRICERATOPS) + MANUF("Applied Magic Inc.", APPLIED_MAGIC) + MANUF("GFX-Base", GFX_BASE) + MANUF("RocTec", ROCTEC) + MANUF("Kato", KATO) + MANUF("Atlantis", ATLANTIS) + MANUF("Protar", PROTAR) + MANUF("ACS", ACS) + MANUF("Software Results Enterprises", SOFTWARE_RESULTS_ENTERPRISES) + MANUF("Masoboshi", MASOBOSHI) + MANUF("Mainhattan-Data (A-Team)", MAINHATTAN_DATA) + MANUF("Village Tronic", VILLAGE_TRONIC) + MANUF("Utilities Unlimited", UTILITIES_UNLIMITED) + MANUF("Amitrix", AMITRIX) + MANUF("ArMax", ARMAX) + MANUF("NewTek", NEWTEK) + MANUF("M-Tech Germany", M_TECH_GERMANY) + MANUF("Great Valley Products", GREAT_VALLEY_PRODUCTS_4) + MANUF("Apollo", APOLLO_1) + MANUF("Ingenieurbüro Helfrich", HELFRICH_2) + MANUF("MacroSystems USA", MACROSYSTEMS_USA) + MANUF("ElBox Computer", ELBOX_COMPUTER) + MANUF("Harms Professional", HARMS_PROFESSIONAL) + MANUF("Micronik", MICRONIK) + MANUF("Micronik", MICRONIK2) + MANUF("MegaMicro", MEGAMICRO) + MANUF("Ronin/Imtronics", IMTRONICS_2) + MANUF("Individual Computers", INDIVIDUAL_COMPUTERS) + MANUF("Kupke", KUPKE_3) + MANUF("ITH", ITH) + MANUF("VMC", VMC) + MANUF("Information", INFORMATION) + MANUF("Vortex", VORTEX) + MANUF("Expansion Systems", EXPANSION_SYSTEMS) + MANUF("ReadySoft", READYSOFT) + MANUF("Phase 5", PHASE5) + MANUF("DPS", DPS) + MANUF("Apollo", APOLLO_2) + MANUF("Apollo", APOLLO_3) + MANUF("Petsoff LP", PETSOFF_LP) + MANUF("Uwe Gerlach", UWE_GERLACH) + MANUF("MacroSystems Germany", MACROSYSTEMS_GERMANY) + MANUF("Combitec", COMBITEC) + MANUF("SKI Peripherals", SKI_PERIPHERALS) + MANUF("Reis-Ware", REIS_WARE_2) + MANUF("Cameron", CAMERON) + MANUF("Reis-Ware", REIS_WARE) + MANUF("Hacker Test Board", HACKER) /* Unused */ + MANUF("Phoenix", PHOENIX_2) + MANUF("Combitec", COMBITEC_2) +END + +#define NUM_MANUF (ARRAYSIZE(Manufacturers)) +#define NUM_GVP_PROD (ARRAYSIZE(Ext_Prod_GVP)) + + + /* + * Zorro product classes + * + * Make sure to keep these in sync with include/linux/zorro.h! + */ + +static const char *classnames[] = { + NULL, /* ZORRO_CLASS_UNKNOWN */ + "ArcNet Card", /* ZORRO_CLASS_ARCNET */ + "Audio Board", /* ZORRO_CLASS_AUDIO */ + "ISA Bus Bridge", /* ZORRO_CLASS_BRIDGE */ + "DSP Board", /* ZORRO_CLASS_DSP */ + "Ethernet Card", /* ZORRO_CLASS_ETHERNET */ + "Ethernet Card and Parallel Ports", /* ZORRO_CLASS_ETHERNET_PARALLEL */ + "Flash ROM", /* ZORRO_CLASS_FLASHROM */ + "FPU and RAM Expansion", /* ZORRO_CLASS_FPU_RAM */ + "Graphics Board", /* ZORRO_CLASS_GFX */ + "Graphics Board (RAM)", /* ZORRO_CLASS_GFXRAM */ + "HD Controller", /* ZORRO_CLASS_HD */ + "HD Controller and RAM Expansion", /* ZORRO_CLASS_HD_RAM */ + "IDE Interface", /* ZORRO_CLASS_IDE */ + "IDE Interface and RAM Expansion", /* ZORRO_CLASS_IDE_RAM */ + "IDE Interface and Floppy Controller", /* ZORRO_CLASS_IDE_FLOPPY */ + "ISDN Interface", /* ZORRO_CLASS_ISDN */ + "Macintosh Emulator", /* ZORRO_CLASS_MACEMU */ + "Miscellaneous Expansion Card", /* ZORRO_CLASS_MISC */ + "Modem", /* ZORRO_CLASS_MODEM */ + "Multi I/O", /* ZORRO_CLASS_MULTIIO */ + "RAM Expansion", /* ZORRO_CLASS_RAM */ + "Scanner Interface", /* ZORRO_CLASS_SCANNER */ + "SCSI Host Adapter", /* ZORRO_CLASS_SCSI */ + "SCSI Host Adapter and IDE Interface", /* ZORRO_CLASS_SCSI_IDE */ + "SCSI Host Adapter and RAM Expansion", /* ZORRO_CLASS_SCSI_RAM */ + "SCSI Host Adapter and Serial Card", /* ZORRO_CLASS_SCSI_SERIAL */ + "Multi Serial", /* ZORRO_CLASS_SERIAL */ + "Drawing Tablet Interface", /* ZORRO_CLASS_TABLET */ + "Accelerator", /* ZORRO_CLASS_TURBO */ + "Accelerator and RAM Expansion", /* ZORRO_CLASS_TURBO_RAM */ + "Accelerator and HD Controller", /* ZORRO_CLASS_TURBO_HD */ + "Accelerator and IDE Interface", /* ZORRO_CLASS_TURBO_IDE */ + "Accelerator and SCSI Host Adapter", /* ZORRO_CLASS_TURBO_SCSI */ + "Accelerator, SCSI Host Adapter and RAM Expansion", /* ZORRO_CLASS_TURBO_SCSI */ + "Video Board", /* ZORRO_CLASS_VIDEO */ +}; + +static inline const char *get_class_name(enum Zorro_Classes class) +{ + if (class < ARRAYSIZE(classnames)) + return(classnames[class]); + else + return("(**Illegal**)"); +} #endif /* CONFIG_ZORRO */ - /* - * Expansion Devices - */ + /* + * Expansion Devices + */ -int zorro_num_autocon; +u_int zorro_num_autocon; struct ConfigDev zorro_autocon[ZORRO_NUM_AUTO]; -static u_long BoardPartFlags[ZORRO_NUM_AUTO] = { 0, }; +static u32 BoardPartFlags[ZORRO_NUM_AUTO] = { 0, }; - /* - * Find the key for the next unconfigured expansion device of a specific - * type. - * - * Part is a device specific number (0 <= part <= 31) to allow for the - * independent configuration of independent parts of an expansion board. - * Thanks to Jes Soerensen for this idea! - * - * Index is used to specify the first board in the autocon list - * to be tested. It was inserted in order to solve the problem - * with the GVP boards that uses the same product code, but - * it should help if there are other companies uses the same - * method as GVP. Drivers for boards which are not using this - * method does not need to think of this - just set index = 0. - * - * Example: - * - * while ((key = zorro_find(MY_MANUF, MY_PROD, MY_PART, 0))) { - * cd = zorro_get_board(key); - * initialise_this_board; - * zorro_config_board(key, MY_PART); - * } - */ + /* + * Find the key for the next unconfigured expansion device of a specific + * type. + * + * Part is a device specific number (0 <= part <= 31) to allow for the + * independent configuration of independent parts of an expansion board. + * Thanks to Jes Soerensen for this idea! + * + * Index is used to specify the first board in the autocon list + * to be tested. It was inserted in order to solve the problem + * with the GVP boards that uses the same product code, but + * it should help if there are other companies which use the same + * method as GVP. Drivers for boards which are not using this + * method do not need to think of this - just set index = 0. + * + * Example: + * + * while ((key = zorro_find(ZORRO_PROD_MY_BOARD, MY_PART, 0))) { + * cd = zorro_get_board(key); + * initialise_this_board; + * zorro_config_board(key, MY_PART); + * } + */ -int zorro_find(int manuf, int prod, int part, int index) +u_int zorro_find(zorro_id id, u_int part, u_int index) { - int key; - struct ConfigDev *cd; - - if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO)) - return(0); - - if ((part < 0) || (part > 31)) { - printk("zorro_find: bad part %d\n", part); - return(0); - } - - for (key = index + 1; key <= zorro_num_autocon; key++) { - cd = &zorro_autocon[key-1]; - if ((cd->cd_Rom.er_Manufacturer == manuf) && - (cd->cd_Rom.er_Product == prod) && - !(BoardPartFlags[key-1] & (1< 31) { + printk("zorro_find: bad part %d\n", part); + return(0); + } + + for (key = index + 1; key <= zorro_num_autocon; key++) { + cd = &zorro_autocon[key-1]; + addr = (u_long)cd->cd_BoardAddr; + if ((cd->cd_Rom.er_Manufacturer == manuf) && + (cd->cd_Rom.er_Product == prod) && + !(BoardPartFlags[key-1] & (1< zorro_num_autocon)) - printk("zorro_get_board: bad key %d\n", key); - else - cd = &zorro_autocon[key-1]; + if ((key < 1) || (key > zorro_num_autocon)) + printk("zorro_get_board: bad key %d\n", key); + else + cd = &zorro_autocon[key-1]; - return(cd); + return(cd); } - /* - * Mark a part of a board as configured - */ + /* + * Mark a part of a board as configured + */ -void zorro_config_board(int key, int part) +void zorro_config_board(u_int key, u_int part) { - if ((key < 1) || (key > zorro_num_autocon)) - printk("zorro_config_board: bad key %d\n", key); - else if ((part < 0) || (part > 31)) - printk("zorro_config_board: bad part %d\n", part); - else - BoardPartFlags[key-1] |= 1< zorro_num_autocon)) + printk("zorro_config_board: bad key %d\n", key); + else if (part > 31) + printk("zorro_config_board: bad part %d\n", part); + else if (BoardPartFlags[key-1] & (1< zorro_num_autocon)) - printk("zorro_unconfig_board: bad key %d\n", key); - else if ((part < 0) || (part > 31)) - printk("zorro_unconfig_board: bad part %d\n", part); - else - BoardPartFlags[key-1] &= ~(1< zorro_num_autocon)) + printk("zorro_unconfig_board: bad key %d\n", key); + else if (part > 31) + printk("zorro_unconfig_board: bad part %d\n", part); + else if (!(BoardPartFlags[key-1] & (1<cd_Rom.er_Manufacturer; - prod = cd->cd_Rom.er_Product; - addr = (u_long)cd->cd_BoardAddr; - size = cd->cd_BoardSize; - configured = BoardPartFlags[devnum] ? '*' : ' '; - manufname = prodname = ""; - - for (i = 0; i < NUM_MANUF; i++) - if (Manufacturers[i].ID == manuf) { - manufname = Manufacturers[i].Name; - for (j = 0; j < Manufacturers[i].NumProd; j++) - if (Manufacturers[i].Products[j].ID == prod) - if ((manuf != MANUF_GVP) || (prod != PROD_GVP)) { - prodname = Manufacturers[i].Products[j].Name; - identified = 1; - break; - } else { - /* - * The epc must be read as a short from the - * hardware. - */ - epc = *(unsigned short *)ZTWO_VADDR(addr+0x8000) & - GVP_PRODMASK; - for (k = 0; k < NUM_GVP_PROD; k++) - if (Ext_Prod_GVP[k].ID == epc) { - prodname = Ext_Prod_GVP[k].Name; - identified = 1; - break; - } - } - break; - } - - switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) { - case ERT_ZORROII: - zorro = '2'; - break; - case ERT_ZORROIII: - zorro = '3'; - break; - default: - zorro = '?'; - break; - } - if (size & 0xfffff) { - size >>= 10; - mag = 'K'; - } else { - size >>= 20; - mag = 'M'; - } - if (cd->cd_Rom.er_Type & ERTF_MEMLIST) - is_mem = " MEM"; - else - is_mem = ""; - - if (identified) - len = sprintf(buf, " %c0x%08lx: %s %s (Z%c, %ld%c%s)\n", configured, addr, - manufname, prodname, zorro, size, mag, is_mem); - else if (manuf == MANUF_HACKER) - len = sprintf(buf, " 0x%08lx: Hacker Test Board 0x%02x (Z%c, %ld%c%s)\n", - addr, prod, zorro, size, mag, is_mem); - else { - len = sprintf(buf, " 0x%08lx: [%04x:%02x] made by %s (Z%c, %ld%c%s)\n", - addr, manuf, prod, manufname, zorro, size, mag, is_mem); - len += sprintf(buf+len, " Please report this unknown device to " - "Geert.Uytterhoeven@cs.kuleuven.ac.be\n"); - } - return(len); + const struct ConfigDev *cd = &zorro_autocon[devnum]; + u32 configured = BoardPartFlags[devnum]; + u_int manuf = cd->cd_Rom.er_Manufacturer; + u_int prod = cd->cd_Rom.er_Product; + u_int class = ZORRO_CLASS_UNKNOWN; + u_int epc = 0; + const char *manufname = "Unknown"; + const char *prodname = "Unknown"; + const char *classname; + u_int i, j, k, len = 0; + u_long addr = (u_long)cd->cd_BoardAddr; + u_long size = cd->cd_BoardSize; + char mag; + int identified = 0, gvp = 0; + + if (manuf != ZORRO_MANUF(ZORRO_PROD_GVP_EPC_BASE) || + prod != ZORRO_PROD(ZORRO_PROD_GVP_EPC_BASE)) { + for (i = 0; i < NUM_MANUF; i++) + if (Manufacturers[i].Manuf == manuf) { + manufname = Manufacturers[i].Name; + for (j = 0; j < Manufacturers[i].NumProd; j++) + if (Manufacturers[i].Products[j].Prod == prod) { + prodname = Manufacturers[i].Products[j].Name; + class = Manufacturers[i].Products[j].Class; + identified = 1; + break; + } + } + /* Put workarounds for ID clashes here */ + if (manuf == ZORRO_MANUF(ZORRO_PROD_HELFRICH_RAINBOW_III) && + prod == ZORRO_PROD(ZORRO_PROD_HELFRICH_RAINBOW_III)) + manufname = "Ingenieurbüro Helfrich"; + } else { + manufname = "Great Valley Products"; + gvp = 1; + epc = *(u_short *)ZTWO_VADDR(addr+0x8000) & GVP_PRODMASK; + for (k = 0; k < NUM_GVP_PROD; k++) + if (epc == Ext_Prod_GVP[k].EPC) { + prodname = Ext_Prod_GVP[k].Name; + class = Ext_Prod_GVP[k].Class; + identified = 1; + break; + } + } + classname = get_class_name(class); + if (size & 0xfffff) { + size >>= 10; + mag = 'K'; + } else { + size >>= 20; + mag = 'M'; + } + if (verbose) { + const char *zorro; + int is_mem = cd->cd_Rom.er_Type & ERTF_MEMLIST; + switch (cd->cd_Rom.er_Type & ERT_TYPEMASK) { + case ERT_ZORROII: + zorro = "Zorro II"; + break; + case ERT_ZORROIII: + zorro = "Zorro III"; + break; + default: + zorro = "Unknown Zorro"; + break; + } + if (!prodname) + prodname = "Unknown"; + if (!classname) + classname = "Unknown"; + len = sprintf(buf, " Device %d at 0x%08lx: ID=%04x:%02x", devnum, + addr, manuf, prod); + if (gvp) + len += sprintf(buf+len, ":%02x", epc); + len += sprintf(buf+len, ", %s, %ld%c", zorro, size, mag); + if (is_mem) + len += sprintf(buf+len, ", System RAM"); + else + len += sprintf(buf+len, ", Configured=%08x", configured); + len += sprintf(buf+len, "\n" + " Manufacturer: %s\n" + " Product Name: %s\n" + " Board Class : %s\n", + manufname, prodname, classname); + } else { + len = sprintf(buf, " %c%08lx: ", configured ? '*' : ' ', addr); + if (identified) { + len += sprintf(buf+len, "%s", manufname); + if (prodname) + len += sprintf(buf+len, " %s", prodname); + if (classname) + len += sprintf(buf+len, " %s", classname); + } else if (manuf == ZORRO_MANUF_HACKER) + len += sprintf(buf+len, "Hacker Test Board %02x", prod); + else if (gvp) + len += sprintf(buf+len, "[%04x:%02x:%02x] made by %s", manuf, prod, + epc, manufname); + else + len += sprintf(buf+len, "[%04x:%02x] made by %s", manuf, prod, + manufname); + len += sprintf(buf+len, " (%ld%c)\n", size, mag); + if (!identified && manuf != ZORRO_MANUF_HACKER) + len += sprintf(buf+len, " Please report this unknown device to " + "zorro@linux-m68k.org\n"); + } + return(len); } - /* - * Identify all known AutoConfig Expansion Devices - */ + /* + * Identify all known AutoConfig Expansion Devices + */ void zorro_identify(void) { - int i; - char tmp[160]; + u_int i; + char tmp[256]; - if (!AMIGAHW_PRESENT(ZORRO)) - return; + if (!AMIGAHW_PRESENT(ZORRO)) + return; - printk("Probing AutoConfig expansion device(s):\n"); - for (i = 0; i < zorro_num_autocon; i++) { - identify(i, tmp); - printk(tmp); - } - if (!zorro_num_autocon) - printk("No AutoConfig expansion devices present.\n"); + printk("Probing AutoConfig expansion device(s):\n"); + for (i = 0; i < zorro_num_autocon; i++) { + identify(i, tmp, 0); + printk(tmp); + } + if (!zorro_num_autocon) + printk("No AutoConfig expansion devices present.\n"); } - /* - * Get the list of all AutoConfig Expansion Devices - */ + /* + * Get the list of all AutoConfig Expansion Devices + */ int zorro_get_list(char *buffer) { - int i, j, len = 0; - char tmp[160]; + u_int i, len = 0, len2; + char tmp[256]; - if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { - len = sprintf(buffer, "AutoConfig expansion devices:\n"); - for (i = 0; i < zorro_num_autocon; i++) { - j = identify(i, tmp); - if (len+j >= 4075) { - len += sprintf(buffer+len, "4K limit reached!\n"); - break; - } - strcpy(buffer+len, tmp); - len += j; - } - } - return(len); + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { + len = sprintf(buffer, "AutoConfig expansion devices:\n"); + for (i = 0; i < zorro_num_autocon; i++) { + len2 = identify(i, tmp, 1); + if (len+len2 >= 4075) { + len += sprintf(buffer+len, "4K limit reached!\n"); + break; + } + strcpy(buffer+len, tmp); + len += len2; + } + } + return(len); } #endif /* CONFIG_ZORRO */ - /* - * Bitmask indicating portions of available Zorro II RAM that are unused - * by the system. Every bit represents a 64K chunk, for a maximum of 8MB - * (128 chunks, physical 0x00200000-0x009fffff). - * - * If you want to use (= allocate) portions of this RAM, you should clear - * the corresponding bits. - * - * Possible uses: - * - z2ram device - * - SCSI DMA bounce buffers - */ + /* + * Bitmask indicating portions of available Zorro II RAM that are unused + * by the system. Every bit represents a 64K chunk, for a maximum of 8MB + * (128 chunks, physical 0x00200000-0x009fffff). + * + * If you want to use (= allocate) portions of this RAM, you should clear + * the corresponding bits. + * + * Possible uses: + * - z2ram device + * - SCSI DMA bounce buffers + */ -u_long zorro_unused_z2ram[4] = { 0, 0, 0, 0 }; +u32 zorro_unused_z2ram[4] = { 0, 0, 0, 0 }; static void mark_region(u_long addr, u_long size, int flag) { - u_long start, end, chunk; + u_long start, end, chunk; - if (flag) { - start = (addr+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; - end = (addr+size) & ~Z2RAM_CHUNKMASK; - } else { - start = addr & ~Z2RAM_CHUNKMASK; - end = (addr+size+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; - } - if (end <= Z2RAM_START || start >= Z2RAM_END) - return; - start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START; - end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START; - while (start < end) { - chunk = start>>Z2RAM_CHUNKSHIFT; - if (flag) - set_bit( chunk, zorro_unused_z2ram ); - else - clear_bit( chunk, zorro_unused_z2ram ); - start += Z2RAM_CHUNKSIZE; - } + if (flag) { + start = (addr+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; + end = (addr+size) & ~Z2RAM_CHUNKMASK; + } else { + start = addr & ~Z2RAM_CHUNKMASK; + end = (addr+size+Z2RAM_CHUNKMASK) & ~Z2RAM_CHUNKMASK; + } + if (end <= Z2RAM_START || start >= Z2RAM_END) + return; + start = start < Z2RAM_START ? 0x00000000 : start-Z2RAM_START; + end = end > Z2RAM_END ? Z2RAM_SIZE : end-Z2RAM_START; + while (start < end) { + chunk = start>>Z2RAM_CHUNKSHIFT; + if (flag) + set_bit( chunk, zorro_unused_z2ram ); + else + clear_bit( chunk, zorro_unused_z2ram ); + start += Z2RAM_CHUNKSIZE; + } } - /* - * Initialization - */ + /* + * Initialization + */ -__initfunc(void zorro_init(void)) +void zorro_init(void) { - int i; - struct ConfigDev *cd; + u_int i; + const struct ConfigDev *cd; - if (!AMIGAHW_PRESENT(ZORRO)) - return; + if (!AMIGAHW_PRESENT(ZORRO)) + return; - /* Mark all available Zorro II memory */ - for (i = 0; i < zorro_num_autocon; i++) { - cd = &zorro_autocon[i]; - if (cd->cd_Rom.er_Type & ERTF_MEMLIST) - mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1); - } - /* Unmark all used Zorro II memory */ - for (i = 0; i < m68k_num_memory; i++) - mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0); + /* Mark all available Zorro II memory */ + for (i = 0; i < zorro_num_autocon; i++) { + cd = &zorro_autocon[i]; + if (cd->cd_Rom.er_Type & ERTF_MEMLIST) + mark_region((u_long)cd->cd_BoardAddr, cd->cd_BoardSize, 1); + } + + /* Unmark all used Zorro II memory */ + for (i = 0; i < m68k_num_memory; i++) + mark_region(m68k_memory[i].addr, m68k_memory[i].size, 0); } diff -ur --new-file old/linux/arch/m68k/apollo/Makefile new/linux/arch/m68k/apollo/Makefile --- old/linux/arch/m68k/apollo/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/apollo/Makefile Fri Feb 13 01:30:12 1998 @@ -0,0 +1,14 @@ +# +# Makefile for Linux arch/m68k/amiga 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 := apollo.o +O_OBJS := config.o dn_ints.o \ + + +include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/m68k/apollo/config.c new/linux/arch/m68k/apollo/config.c --- old/linux/arch/m68k/apollo/config.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/apollo/config.c Fri Feb 13 01:30:12 1998 @@ -0,0 +1,245 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern struct consw fb_con; +extern void dn_sched_init(void (*handler)(int,void *,struct pt_regs *)); +extern int dn_keyb_init(void); +extern int dn_dummy_kbdrate(struct kbd_repeat *); +extern void dn_init_IRQ(void); +#if 0 +extern void (*dn_default_handler[])(int,void *,struct pt_regs *); +#endif +extern int dn_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); +extern void dn_free_irq(unsigned int irq, void *dev_id); +extern void dn_enable_irq(unsigned int); +extern void dn_disable_irq(unsigned int); +extern int dn_get_irq_list(char *); +extern unsigned long dn_gettimeoffset(void); +extern void dn_gettod(int *, int *, int *, int *, int *, int *); +extern int dn_dummy_hwclk(int, struct hwclk_time *); +extern int dn_dummy_set_clock_mmss(unsigned long); +extern void dn_mksound(unsigned int count, unsigned int ticks); +extern void dn_dummy_reset(void); +extern void dn_dummy_waitbut(void); +extern struct fb_info *dn_fb_init(long *); +extern void dn_dummy_debug_init(void); +extern void (*kd_mksound)(unsigned int, unsigned int); +extern void dn_dummy_video_setup(char *,int *); +extern void dn_process_int(int irq, struct pt_regs *fp); + +static struct console dn_console_driver; +static void dn_debug_init(void); +static void dn_timer_int(int irq,void *, struct pt_regs *); +static void (*sched_timer_handler)(int, void *, struct pt_regs *)=NULL; + +int dn_serial_console_wait_key(void) { + + while(!(sio01.srb_csrb & 1)) + barrier(); + return sio01.rhrb_thrb; +} + +void dn_serial_console_write (const char *str,unsigned int count) +{ + while(count--) { + if (*str == '\n') { + sio01.rhrb_thrb = (unsigned char)'\r'; + while (!(sio01.srb_csrb & 0x4)) + ; + } + sio01.rhrb_thrb = (unsigned char)*str++; + while (!(sio01.srb_csrb & 0x4)) + ; + } +} + +void dn_serial_print (const char *str) +{ + while (*str) { + if (*str == '\n') { + sio01.rhrb_thrb = (unsigned char)'\r'; + while (!(sio01.srb_csrb & 0x4)) + ; + } + sio01.rhrb_thrb = (unsigned char)*str++; + while (!(sio01.srb_csrb & 0x4)) + ; + } +} + +void config_apollo(void) { + + dn_serial_print("Config apollo !\n"); +#if 0 + dn_debug_init(); +#endif + printk("Config apollo !\n"); + + + mach_sched_init=dn_sched_init; /* */ + mach_keyb_init=dn_keyb_init; + mach_kbdrate=dn_dummy_kbdrate; + mach_init_IRQ=dn_init_IRQ; + mach_default_handler=NULL; + mach_request_irq = dn_request_irq; + mach_free_irq = dn_free_irq; + enable_irq = dn_enable_irq; + disable_irq = dn_disable_irq; + mach_get_irq_list = dn_get_irq_list; + mach_gettimeoffset = dn_gettimeoffset; + mach_gettod = dn_gettod; /* */ + mach_max_dma_address = 0xffffffff; + mach_hwclk = dn_dummy_hwclk; /* */ + mach_set_clock_mmss = dn_dummy_set_clock_mmss; /* */ + mach_process_int = dn_process_int; +#ifdef CONFIG_BLK_DEV_FD + mach_floppy_init = dn_dummy_floppy_init; + mach_floppy_setup = dn_dummy_floppy_setup; +#endif + mach_reset = dn_dummy_reset; /* */ + conswitchp = &fb_con; +#if 0 + mach_fb_init = dn_fb_init; + mach_video_setup = dn_dummy_video_setup; +#endif + kd_mksound = dn_mksound; + +} + +void dn_timer_int(int irq, void *dev_id, struct pt_regs *fp) { + + volatile unsigned char x; + + sched_timer_handler(irq,dev_id,fp); + + x=*(volatile unsigned char *)(IO_BASE+0x10803); + x=*(volatile unsigned char *)(IO_BASE+0x10805); + +} + +void dn_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)) { + + dn_serial_print("dn sched_init\n"); + +#if 0 + /* program timer 2 */ + *(volatile unsigned char *)(IO_BASE+0x10803)=0x00; + *(volatile unsigned char *)(IO_BASE+0x10809)=0; + *(volatile unsigned char *)(IO_BASE+0x1080b)=50; + + /* program timer 3 */ + *(volatile unsigned char *)(IO_BASE+0x10801)=0x00; + *(volatile unsigned char *)(IO_BASE+0x1080c)=0; + *(volatile unsigned char *)(IO_BASE+0x1080f)=50; +#endif + /* program timer 1 */ + *(volatile unsigned char *)(IO_BASE+0x10803)=0x01; + *(volatile unsigned char *)(IO_BASE+0x10801)=0x40; + *(volatile unsigned char *)(IO_BASE+0x10805)=0x09; + *(volatile unsigned char *)(IO_BASE+0x10807)=0xc4; + + /* enable IRQ of PIC B */ + *(volatile unsigned char *)(IO_BASE+PICA+1)&=(~8); + + + + printk("*(0x10803) %02x\n",*(volatile unsigned char *)(IO_BASE+0x10803)); + printk("*(0x10803) %02x\n",*(volatile unsigned char *)(IO_BASE+0x10803)); + + sched_timer_handler=timer_routine; + request_irq(0,dn_timer_int,0,NULL,NULL); + + +} + +unsigned long dn_gettimeoffset(void) { + + return 0xdeadbeef; + +} + +void dn_gettod(int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) { + + *yearp=rtc->year; + *monp=rtc->month; + *dayp=rtc->day_of_month; + *hourp=rtc->hours; + *minp=rtc->minute; + *secp=rtc->second; + +printk("gettod: %d %d %d %d %d %d\n",*yearp,*monp,*dayp,*hourp,*minp,*secp); + +} + +int dn_dummy_hwclk(int op, struct hwclk_time *t) { + + dn_serial_print("hwclk !\n"); + + if(!op) { /* read */ + t->sec=rtc->second; + t->min=rtc->minute; + t->hour=rtc->hours; + t->day=rtc->day_of_month; + t->wday=rtc->day_of_week; + t->mon=rtc->month; + t->year=rtc->year; + } else { + rtc->second=t->sec; + rtc->minute=t->min; + rtc->hours=t->hour; + rtc->day_of_month=t->day; + if(t->wday!=-1) + rtc->day_of_week=t->wday; + rtc->month=t->mon; + rtc->year=t->year; + } + + dn_serial_print("hwclk end!\n"); + return 0; + +} + +int dn_dummy_set_clock_mmss(unsigned long nowtime) { + + printk("set_clock_mmss\n"); + + return 0; + +} + +void dn_dummy_reset(void) { + + dn_serial_print("The end !\n"); + + for(;;); + +} + +void dn_dummy_waitbut(void) { + + dn_serial_print("waitbut\n"); + +} + +#if 0 +void dn_debug_init(void) { + + dn_console_driver.write=dn_serial_console_write; + register_console(&dn_console_driver); + +} +#endif diff -ur --new-file old/linux/arch/m68k/apollo/dn_debug.c new/linux/arch/m68k/apollo/dn_debug.c --- old/linux/arch/m68k/apollo/dn_debug.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/apollo/dn_debug.c Fri Feb 13 01:30:12 1998 @@ -0,0 +1,23 @@ +#include + +#define DN_DEBUG_BUFFER_BASE 0x82800000 +#define DN_DEBUG_BUFFER_SIZE 8*1024*1024 + +static char *current_dbg_ptr=DN_DEBUG_BUFFER_BASE; + +int dn_deb_printf(const char *fmt, ...) { + + va_list args; + int i; + + if(current_dbg_ptr<(DN_DEBUG_BUFFER_BASE + DN_DEBUG_BUFFER_SIZE)) { + va_start(args,fmt); + i=vsprintf(current_dbg_ptr,fmt,args); + va_end(args); + current_dbg_ptr+=i; + + return i; + } + else + return 0; +} diff -ur --new-file old/linux/arch/m68k/apollo/dn_ints.c new/linux/arch/m68k/apollo/dn_ints.c --- old/linux/arch/m68k/apollo/dn_ints.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/apollo/dn_ints.c Fri Feb 13 01:30:12 1998 @@ -0,0 +1,166 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static irq_handler_t dn_irqs[16]; + +extern void write_keyb_cmd(u_short length, u_char *cmd); +static char BellOnCommand[] = { 0xFF, 0x21, 0x81 }, + BellOffCommand[] = { 0xFF, 0x21, 0x82 }; + +void dn_process_int(int irq, struct pt_regs *fp) { + +#if 0 + unsigned char x; +#endif + +#if 0 + printk("Aha DN interrupt ! : %d\n",irq); +#endif + + if(dn_irqs[irq-160].handler) { + dn_irqs[irq-160].handler(irq,dn_irqs[irq-160].dev_id,fp); + } + else { + printk("spurious irq %d occured\n",irq); + } + +#if 0 + printk("*(0x10803) %02x\n",*(volatile unsigned char *)(IO_BASE+0x10803)); + x=*(volatile unsigned char *)(IO_BASE+0x10805); +#endif + + *(volatile unsigned char *)(IO_BASE+0x11000)=0x20; + *(volatile unsigned char *)(IO_BASE+0x11100)=0x20; + +} + +void dn_init_IRQ(void) { + + int i; + + printk("Init IRQ\n"); + + for(i=0;i<16;i++) { + dn_irqs[i].handler=NULL; + dn_irqs[i].flags=IRQ_FLG_STD; + dn_irqs[i].dev_id=NULL; + dn_irqs[i].devname=NULL; + } + +} + +int dn_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) { + + printk("dn request IRQ\n"); + + if((irq<0) || (irq>15)) { + printk("Trying to request illegal IRQ\n"); + return -ENXIO; + } + + if(!dn_irqs[irq].handler) { + dn_irqs[irq].handler=handler; + dn_irqs[irq].flags=IRQ_FLG_STD; + dn_irqs[irq].dev_id=dev_id; + dn_irqs[irq].devname=devname; + if(irq<8) + *(volatile unsigned char *)(IO_BASE+PICA+1)&=~(1<15)) { + printk("Trying to free illegal IRQ\n"); + return ; + } + + if(irq<8) + *(volatile unsigned char *)(IO_BASE+PICA+1)|=(1< IRQ_TYPE_PRIO) { printk ("%s: Bad irq type %ld requested from %s\n", __FUNCTION__, flags, devname); @@ -600,11 +612,11 @@ continue; if (i < STMFP_SOURCE_BASE) len += sprintf(buf+len, "auto %2d: %10u ", - i, kstat.interrupts[i]); + i, kstat.irqs[0][i]); else len += sprintf(buf+len, "vec $%02x: %10u ", IRQ_SOURCE_TO_VECTOR(i), - kstat.interrupts[i]); + kstat.irqs[0][i]); if (irq_handler[i].handler != atari_call_irq_list) { len += sprintf(buf+len, "%s\n", irq_param[i].devname); 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 Mon Jul 7 17:18:53 1997 +++ new/linux/arch/m68k/atari/atakeyb.c Fri Feb 13 01:30:12 1998 @@ -32,7 +32,6 @@ #include #include -extern int ovsc_switchmode; extern unsigned char mach_keyboard_type; static void atakeyb_rep( unsigned long ignore ); extern unsigned int keymap_count; @@ -504,23 +503,6 @@ } } -#ifdef KEYB_WRITE_INTERRUPT - if (acia_stat & ACIA_TDRE) /* transmit of character is finished */ - { - if (kb_state.buf) - { - acia.key_data = *kb_state.buf++; - kb_state.len--; - if (kb_state.len == 0) - { - kb_state.buf = NULL; - if (!kb_state.kernel_mode) - /* unblock something */; - } - } - } -#endif - #if 0 if (acia_stat & ACIA_CTS) /* cannot happen */; @@ -537,26 +519,6 @@ goto repeat; } -#ifdef KEYB_WRITE_INTERRUPT -void ikbd_write(const char *str, int len) -{ - u_char acia_stat; - - if (kb_stat.buf) - /* wait */; - acia_stat = acia.key_ctrl; - if (acia_stat & ACIA_TDRE) - { - if (len != 1) - { - kb_stat.buf = str + 1; - kb_stat.len = len - 1; - } - acia.key_data = *str; - /* poll */ - } -} -#else /* * I write to the keyboard without using interrupts, I poll instead. * This takes for the maximum length string allowed (7) at 7812.5 baud @@ -581,7 +543,6 @@ } } } -#endif /* Reset (without touching the clock) */ void ikbd_reset(void) @@ -828,33 +789,28 @@ atari_turnoff_irq(IRQ_MFP_ACIA); do { - acia.key_ctrl = ACIA_RESET; /* reset ACIA */ + /* reset IKBD ACIA */ + acia.key_ctrl = ACIA_RESET | + (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0; (void)acia.key_ctrl; (void)acia.key_data; - acia.mid_ctrl = ACIA_RESET; /* reset other ACIA */ + /* reset MIDI ACIA */ + acia.mid_ctrl = ACIA_RESET | + (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; (void)acia.mid_ctrl; (void)acia.mid_data; /* divide 500kHz by 64 gives 7812.5 baud */ /* 8 data no parity 1 start 1 stop bit */ /* receive interrupt enabled */ -#ifdef KEYB_WRITE_INTERRUPT - /* RTS low, transmit interrupt enabled */ - if (ovsc_switchmode == 1) - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTIE|ACIA_RIE); - /* switch on OverScan via keyboard ACIA */ - else - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTIE|ACIA_RIE); -#else - /* RTS low, transmit interrupt disabled */ - if (ovsc_switchmode == 1) - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RHTID|ACIA_RIE); - else - acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RLTID|ACIA_RIE); -#endif + /* RTS low (except if switch selected), transmit interrupt disabled */ + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) | + ((atari_switches & ATARI_SWITCH_IKBD) ? + ACIA_RHTID : ACIA_RLTID); - acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S; + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | + (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; } /* make sure the interrupt line is up */ while ((mfp.par_dt_reg & 0x10) == 0); diff -ur --new-file old/linux/arch/m68k/atari/atari_ksyms.c new/linux/arch/m68k/atari/atari_ksyms.c --- old/linux/arch/m68k/atari/atari_ksyms.c Thu Apr 24 04:01:15 1997 +++ new/linux/arch/m68k/atari/atari_ksyms.c Wed Mar 18 06:15:40 1998 @@ -1,5 +1,6 @@ -#include #include +#include + #include #include #include @@ -7,24 +8,32 @@ #include #include #include +#include extern void atari_microwire_cmd( int cmd ); +extern int atari_MFP_init_done; +extern int atari_SCC_init_done; extern int atari_SCC_reset_done; EXPORT_SYMBOL(atari_mch_cookie); +EXPORT_SYMBOL(atari_mch_type); EXPORT_SYMBOL(atari_hw_present); -EXPORT_SYMBOL(is_medusa); -EXPORT_SYMBOL(is_hades); +EXPORT_SYMBOL(atari_switches); +EXPORT_SYMBOL(atari_dont_touch_floppy_select); EXPORT_SYMBOL(atari_register_vme_int); EXPORT_SYMBOL(atari_unregister_vme_int); EXPORT_SYMBOL(stdma_lock); EXPORT_SYMBOL(stdma_release); EXPORT_SYMBOL(stdma_others_waiting); EXPORT_SYMBOL(stdma_islocked); +EXPORT_SYMBOL(atari_stram_alloc); +EXPORT_SYMBOL(atari_stram_free); EXPORT_SYMBOL(atari_mouse_buttons); EXPORT_SYMBOL(atari_mouse_interrupt_hook); EXPORT_SYMBOL(atari_MIDI_interrupt_hook); +EXPORT_SYMBOL(atari_MFP_init_done); +EXPORT_SYMBOL(atari_SCC_init_done); EXPORT_SYMBOL(atari_SCC_reset_done); EXPORT_SYMBOL(ikbd_write); EXPORT_SYMBOL(ikbd_mouse_y0_top); @@ -33,3 +42,7 @@ EXPORT_SYMBOL(ikbd_mouse_disable); EXPORT_SYMBOL(atari_microwire_cmd); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff -ur --new-file old/linux/arch/m68k/atari/atasound.c new/linux/arch/m68k/atari/atasound.c --- old/linux/arch/m68k/atari/atasound.c Fri Dec 20 10:19:58 1996 +++ new/linux/arch/m68k/atari/atasound.c Fri Feb 13 01:30:12 1998 @@ -1,17 +1,16 @@ /* -linux/arch/m68k/atari/atasound.c - -++Geert: Moved almost all stuff to linux/drivers/sound/ - -The author of atari_nosound, atari_mksound and atari_microwire_cmd is -unknown. -(++roman: That's me... :-) - -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. - -*/ + * linux/arch/m68k/atari/atasound.c + * + * ++Geert: Moved almost all stuff to linux/drivers/sound/ + * + * The author of atari_nosound, atari_mksound and atari_microwire_cmd is + * unknown. (++roman: That's me... :-) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ #include diff -ur --new-file old/linux/arch/m68k/atari/config.c new/linux/arch/m68k/atari/config.c --- old/linux/arch/m68k/atari/config.c Wed May 14 07:41:02 1997 +++ new/linux/arch/m68k/atari/config.c Fri Feb 13 01:30:12 1998 @@ -27,35 +27,33 @@ #include #include #include -#include -#include -#include #include -#include #include +#include #include #include #include -#include #include - +#include #include -#include -#include -#include #include -#ifdef CONFIG_KGDB -#include -#endif - u_long atari_mch_cookie; +u_long atari_mch_type = 0; struct atari_hw_present atari_hw_present; +u_long atari_switches = 0; +int atari_dont_touch_floppy_select = 0; +int atari_rtc_year_offset; -extern char m68k_debug_device[]; +/* local function prototypes */ +static void atari_reset( void ); +#ifdef CONFIG_ATARI_FLOPPY +extern void atari_floppy_setup(char *, int *); +#endif +static void atari_get_model(char *model); +static int atari_get_hardware_list(char *buffer); -static void atari_sched_init(void (*)(int, void *, struct pt_regs *)); /* atari specific keyboard functions */ extern int atari_keyb_init(void); extern int atari_kbdrate (struct kbd_repeat *); @@ -68,33 +66,36 @@ extern void atari_enable_irq (unsigned int); extern void atari_disable_irq (unsigned int); extern int atari_get_irq_list (char *buf); -static void atari_get_model(char *model); -static int atari_get_hardware_list(char *buffer); -/* atari specific timer functions */ -static unsigned long atari_gettimeoffset (void); -static void atari_mste_gettod (int *, int *, int *, int *, int *, int *); -static void atari_gettod (int *, int *, int *, int *, int *, int *); -static int atari_mste_hwclk (int, struct hwclk_time *); -static int atari_hwclk (int, struct hwclk_time *); -static int atari_mste_set_clock_mmss (unsigned long); -static int atari_set_clock_mmss (unsigned long); extern void atari_mksound( unsigned int count, unsigned int ticks ); -static void atari_reset( void ); -#ifdef CONFIG_BLK_DEV_FD -extern int atari_floppy_init (void); -extern void atari_floppy_setup(char *, int *); +#ifdef CONFIG_HEARTBEAT +static void atari_heartbeat( int on ); #endif extern struct consw fb_con; -extern struct fb_info *atari_fb_init(long *); -static void atari_debug_init(void); -extern void atari_video_setup(char *, int *); - -static struct console atari_console_driver; - -/* Can be set somewhere, if a SCC master reset has already be done and should - * not be repeated; used by kgdb */ -int atari_SCC_reset_done = 0; +/* atari specific timer functions (in time.c) */ +extern void atari_sched_init(void (*)(int, void *, struct pt_regs *)); +extern unsigned long atari_gettimeoffset (void); +extern void atari_mste_gettod (int *, int *, int *, int *, int *, int *); +extern void atari_tt_gettod (int *, int *, int *, int *, int *, int *); +extern int atari_mste_hwclk (int, struct hwclk_time *); +extern int atari_tt_hwclk (int, struct hwclk_time *); +extern int atari_mste_set_clock_mmss (unsigned long); +extern int atari_tt_set_clock_mmss (unsigned long); + +/* atari specific debug functions (in debug.c) */ +extern void atari_debug_init(void); + +#ifdef CONFIG_MAGIC_SYSRQ +static char atari_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */ + "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\000\000\000()/*789456123" /* 0x60 - 0x6f */ + "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ +#endif extern void (*kd_mksound)(unsigned int, unsigned int); @@ -237,18 +238,62 @@ case BI_ATARI_MCH_COOKIE: atari_mch_cookie = *data; break; + case BI_ATARI_MCH_TYPE: + atari_mch_type = *data; + break; default: unknown = 1; } return(unknown); } + +/* Parse the Atari-specific switches= option. */ +__initfunc(void atari_switches_setup( const char *str, unsigned len )) +{ + char switches[len+1]; + char *p; + int ovsc_shift; + + /* copy string to local array, strtok works destructively... */ + strncpy( switches, str, len ); + switches[len] = 0; + atari_switches = 0; + + /* parse the options */ + for( p = strtok( switches, "," ); p; p = strtok( NULL, "," ) ) { + ovsc_shift = 0; + if (strncmp( p, "ov_", 3 ) == 0) { + p += 3; + ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; + } + + if (strcmp( p, "ikbd" ) == 0) { + /* RTS line of IKBD ACIA */ + atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; + } + else if (strcmp( p, "midi" ) == 0) { + /* RTS line of MIDI ACIA */ + atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; + } + else if (strcmp( p, "snd6" ) == 0) { + atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; + } + else if (strcmp( p, "snd7" ) == 0) { + atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; + } + } +} + + /* * Setup the Atari configuration info */ __initfunc(void config_atari(void)) { + unsigned short tos_version; + memset(&atari_hw_present, 0, sizeof(atari_hw_present)); atari_debug_init(); @@ -267,22 +312,40 @@ mach_get_irq_list = atari_get_irq_list; mach_gettimeoffset = atari_gettimeoffset; mach_reset = atari_reset; -#ifdef CONFIG_BLK_DEV_FD - mach_floppy_init = atari_floppy_init; +#ifdef CONFIG_ATARI_FLOPPY mach_floppy_setup = atari_floppy_setup; #endif conswitchp = &fb_con; - mach_fb_init = atari_fb_init; mach_max_dma_address = 0xffffff; - mach_video_setup = atari_video_setup; kd_mksound = atari_mksound; +#ifdef CONFIG_MAGIC_SYSRQ + mach_sysrq_key = 98; /* HELP */ + mach_sysrq_shift_state = 8; /* Alt */ + mach_sysrq_shift_mask = 0xff; /* all modifiers except CapsLock */ + mach_sysrq_xlate = atari_sysrq_xlate; +#endif +#ifdef CONFIG_HEARTBEAT + mach_heartbeat = atari_heartbeat; +#endif + /* Set switches as requested by the user */ + if (atari_switches & ATARI_SWITCH_IKBD) + acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & ATARI_SWITCH_MIDI) + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | + ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | + ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); + } + /* ++bjoern: * Determine hardware present */ printk( "Atari hardware found: " ); - if (is_medusa || is_hades) { + if (MACH_IS_MEDUSA || MACH_IS_HADES) { /* There's no Atari video hardware on the Medusa, but all the * addresses below generate a DTACK so no bus error occurs! */ } @@ -324,12 +387,12 @@ ATARIHW_SET(SCSI_DMA); printk( "TT_SCSI_DMA " ); } - if (!is_hades && hwreg_present( &st_dma.dma_hi )) { + if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) { ATARIHW_SET(STND_DMA); printk( "STND_DMA " ); } - if (is_medusa || /* The ST-DMA address registers aren't readable - * on all Medusas, so the test below may fail */ + if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable + * on all Medusas, so the test below may fail */ (hwreg_present( &st_dma.dma_vhi ) && (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && @@ -346,11 +409,12 @@ ATARIHW_SET(YM_2149); printk( "YM2149 " ); } - if (!is_medusa && !is_hades && hwreg_present( &tt_dmasnd.ctrl )) { + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && + hwreg_present( &tt_dmasnd.ctrl )) { ATARIHW_SET(PCM_8BIT); printk( "PCM " ); } - if (!is_hades && hwreg_present( &codec.unused5 )) { + if (!MACH_IS_HADES && hwreg_present( &codec.unused5 )) { ATARIHW_SET(CODEC); printk( "CODEC " ); } @@ -364,7 +428,7 @@ (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) #else - !is_medusa && !is_hades + !MACH_IS_MEDUSA && !MACH_IS_HADES #endif ) { ATARIHW_SET(SCC_DMA); @@ -378,7 +442,7 @@ ATARIHW_SET( ST_ESCC ); printk( "ST_ESCC " ); } - if (is_hades) + if (MACH_IS_HADES) { ATARIHW_SET( VME ); printk( "VME " ); @@ -393,20 +457,22 @@ ATARIHW_SET(ANALOG_JOY); printk( "ANALOG_JOY " ); } - if (!is_hades && hwreg_present( blitter.halftone )) { + if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) { ATARIHW_SET(BLITTER); printk( "BLITTER " ); } - if (hwreg_present( (void *)(ATA_HD_BASE+ATA_HD_CMD) )) { + if (hwreg_present((void *)0xfff00039)) { ATARIHW_SET(IDE); printk( "IDE " ); } #if 1 /* This maybe wrong */ - if (!is_medusa && !is_hades && + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && hwreg_present( &tt_microwire.data ) && hwreg_present( &tt_microwire.mask ) && (tt_microwire.mask = 0x7ff, + udelay(1), tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, + udelay(1), tt_microwire.data != 0)) { ATARIHW_SET(MICROWIRE); while (tt_microwire.mask != 0x7ff) ; @@ -416,24 +482,24 @@ if (hwreg_present( &tt_rtc.regsel )) { ATARIHW_SET(TT_CLK); printk( "TT_CLK " ); - mach_gettod = atari_gettod; - mach_hwclk = atari_hwclk; - mach_set_clock_mmss = atari_set_clock_mmss; + mach_gettod = atari_tt_gettod; + mach_hwclk = atari_tt_hwclk; + mach_set_clock_mmss = atari_tt_set_clock_mmss; } - if (!is_hades && hwreg_present( &mste_rtc.sec_ones)) { + if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) { ATARIHW_SET(MSTE_CLK); printk( "MSTE_CLK "); mach_gettod = atari_mste_gettod; mach_hwclk = atari_mste_hwclk; mach_set_clock_mmss = atari_mste_set_clock_mmss; } - if (!is_medusa && !is_hades && + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && hwreg_present( &dma_wd.fdc_speed ) && hwreg_write( &dma_wd.fdc_speed, 0 )) { ATARIHW_SET(FDCSPEED); printk( "FDC_SPEED "); } - if (!is_hades && !ATARIHW_PRESENT(ST_SCSI)) { + if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { ATARIHW_SET(ACSI); printk( "ACSI " ); } @@ -491,153 +557,24 @@ : "d0" ); } -} - -__initfunc(static void -atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) -{ - /* set Timer C data Register */ - mfp.tim_dt_c = INT_TICKS; - /* start timer C, div = 1:100 */ - mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; - /* install interrupt service routine for MFP Timer C */ - request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, - "timer", timer_routine); -} - -/* ++andreas: gettimeoffset fixed to check for pending interrupt */ - -#define TICK_SIZE 10000 - -/* This is always executed with interrupts disabled. */ -static unsigned long atari_gettimeoffset (void) -{ - unsigned long ticks, offset = 0; - /* read MFP timer C current value */ - ticks = mfp.tim_dt_c; - /* The probability of underflow is less than 2% */ - if (ticks > INT_TICKS - INT_TICKS / 50) - /* Check for pending timer interrupt */ - if (mfp.int_pn_b & (1 << 5)) - offset = TICK_SIZE; - - ticks = INT_TICKS - ticks; - ticks = ticks * 10000L / INT_TICKS; - - return ticks + offset; -} - - -static void -mste_read(struct MSTE_RTC *val) -{ -#define COPY(v) val->v=(mste_rtc.v & 0xf) - do { - COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; - COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; - COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; - COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; - COPY(year_tens) ; - /* prevent from reading the clock while it changed */ - } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); -#undef COPY -} - -static void -mste_write(struct MSTE_RTC *val) -{ -#define COPY(v) mste_rtc.v=val->v - do { - COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; - COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; - COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; - COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; - COPY(year_tens) ; - /* prevent from writing the clock while it changed */ - } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); -#undef COPY -} - -#define RTC_READ(reg) \ - ({ unsigned char __val; \ - outb(reg,&tt_rtc.regsel); \ - __val = tt_rtc.data; \ - __val; \ - }) - -#define RTC_WRITE(reg,val) \ - do { \ - outb(reg,&tt_rtc.regsel); \ - tt_rtc.data = (val); \ - } while(0) - - -static void atari_mste_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - int hr24=0, hour; - struct MSTE_RTC val; - - mste_rtc.mode=(mste_rtc.mode | 1); - hr24=mste_rtc.mon_tens & 1; - mste_rtc.mode=(mste_rtc.mode & ~1); - - mste_read(&val); - *secp = val.sec_ones + val.sec_tens * 10; - *minp = val.min_ones + val.min_tens * 10; - hour = val.hr_ones + val.hr_tens * 10; - if (!hr24) { - if (hour == 12 || hour == 12 + 20) - hour -= 12; - if (hour >= 20) - hour += 12 - 20; - } - *hourp = hour; - *dayp = val.day_ones + val.day_tens * 10; - *monp = val.mon_ones + val.mon_tens * 10; - *yearp = val.year_ones + val.year_tens * 10 + 80; -} - - -static void atari_gettod (int *yearp, int *monp, int *dayp, - int *hourp, int *minp, int *secp) -{ - unsigned char ctrl; - unsigned short tos_version; - int hour, pm; - - while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ; - while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ; + /* + * On the Hades map the PCI memory, I/O and configuration areas + * (0x80000000 - 0xbfffffff). + * + * Settings: supervisor only, non-cacheable, serialized, read and write. + */ - *secp = RTC_READ(RTC_SECONDS); - *minp = RTC_READ(RTC_MINUTES); - hour = RTC_READ(RTC_HOURS); - *dayp = RTC_READ(RTC_DAY_OF_MONTH); - *monp = RTC_READ(RTC_MONTH); - *yearp = RTC_READ(RTC_YEAR); - pm = hour & 0x80; - hour &= ~0x80; - - ctrl = RTC_READ(RTC_CONTROL); - - if (!(ctrl & RTC_DM_BINARY)) { - BCD_TO_BIN(*secp); - BCD_TO_BIN(*minp); - BCD_TO_BIN(hour); - BCD_TO_BIN(*dayp); - BCD_TO_BIN(*monp); - BCD_TO_BIN(*yearp); - } - if (!(ctrl & RTC_24H)) { - if (!pm && hour == 12) - hour = 0; - else if (pm && hour != 12) - hour += 12; + if (MACH_IS_HADES) { + __asm__ __volatile__ ("movel %0,%/d0\n\t" + ".chip 68040\n\t" + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%dtt0\n\t" + ".chip 68k\n\t" + : /* no outputs */ + : "g" (0x803fa040) + : "d0"); } - *hourp = hour; - - /* Adjust values (let the setup valid) */ /* Fetch tos version at Physical 2 */ /* We my not be able to access this address if the kernel is @@ -647,403 +584,29 @@ we use the fact that in head.S we have set up a mapping 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible in the last 16MB of the address space. */ - tos_version = (is_medusa || is_hades) ? 0xfff : *(unsigned short *)0xFF000002; - *yearp += (tos_version < 0x306) ? 70 : 68; + tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? + 0xfff : *(unsigned short *)0xff000002; + atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; } -#define HWCLK_POLL_INTERVAL 5 - -static int atari_mste_hwclk( int op, struct hwclk_time *t ) +#ifdef CONFIG_HEARTBEAT +static void atari_heartbeat( int on ) { - int hour, year; - int hr24=0; - struct MSTE_RTC val; - - mste_rtc.mode=(mste_rtc.mode | 1); - hr24=mste_rtc.mon_tens & 1; - mste_rtc.mode=(mste_rtc.mode & ~1); - - if (op) { - /* write: prepare values */ - - val.sec_ones = t->sec % 10; - val.sec_tens = t->sec / 10; - val.min_ones = t->min % 10; - val.min_tens = t->min / 10; - hour = t->hour; - if (!hr24) { - if (hour > 11) - hour += 20 - 12; - if (hour == 0 || hour == 20) - hour += 12; - } - val.hr_ones = hour % 10; - val.hr_tens = hour / 10; - val.day_ones = t->day % 10; - val.day_tens = t->day / 10; - val.mon_ones = (t->mon+1) % 10; - val.mon_tens = (t->mon+1) / 10; - year = t->year - 80; - val.year_ones = year % 10; - val.year_tens = year / 10; - val.weekday = t->wday; - mste_write(&val); - mste_rtc.mode=(mste_rtc.mode | 1); - val.year_ones = (year % 4); /* leap year register */ - mste_rtc.mode=(mste_rtc.mode & ~1); - } - else { - mste_read(&val); - t->sec = val.sec_ones + val.sec_tens * 10; - t->min = val.min_ones + val.min_tens * 10; - hour = val.hr_ones + val.hr_tens * 10; - if (!hr24) { - if (hour == 12 || hour == 12 + 20) - hour -= 12; - if (hour >= 20) - hour += 12 - 20; - } - t->hour = hour; - t->day = val.day_ones + val.day_tens * 10; - t->mon = val.mon_ones + val.mon_tens * 10 - 1; - t->year = val.year_ones + val.year_tens * 10 + 80; - t->wday = val.weekday; - } - return 0; -} + unsigned char tmp; + unsigned long flags; -static int atari_hwclk( int op, struct hwclk_time *t ) -{ - int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; - unsigned long flags; - unsigned short tos_version; - unsigned char ctrl; - int pm = 0; - - /* Tos version at Physical 2. See above for explanation why we - cannot use PTOV(2). */ - tos_version = (is_medusa || is_hades) ? 0xfff : *(unsigned short *)0xff000002; - - ctrl = RTC_READ(RTC_CONTROL); /* control registers are - * independent from the UIP */ - - if (op) { - /* write: prepare values */ - - sec = t->sec; - min = t->min; - hour = t->hour; - day = t->day; - mon = t->mon + 1; - year = t->year - ((tos_version < 0x306) ? 70 : 68); - wday = t->wday + (t->wday >= 0); - - if (!(ctrl & RTC_24H)) { - if (hour > 11) { - pm = 0x80; - if (hour != 12) - hour -= 12; - } - else if (hour == 0) - hour = 12; - } - - if (!(ctrl & RTC_DM_BINARY)) { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hour); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(year); - if (wday >= 0) BIN_TO_BCD(wday); - } - } + if (atari_dont_touch_floppy_select) + return; - /* Reading/writing the clock registers is a bit critical due to - * the regular update cycle of the RTC. While an update is in - * progress, registers 0..9 shouldn't be touched. - * The problem is solved like that: If an update is currently in - * progress (the UIP bit is set), the process sleeps for a while - * (50ms). This really should be enough, since the update cycle - * normally needs 2 ms. - * If the UIP bit reads as 0, we have at least 244 usecs until the - * update starts. This should be enough... But to be sure, - * additionally the RTC_SET bit is set to prevent an update cycle. - */ - - while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HWCLK_POLL_INTERVAL; - schedule(); - } - save_flags(flags); cli(); - RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); - if (!op) { - sec = RTC_READ( RTC_SECONDS ); - min = RTC_READ( RTC_MINUTES ); - hour = RTC_READ( RTC_HOURS ); - day = RTC_READ( RTC_DAY_OF_MONTH ); - mon = RTC_READ( RTC_MONTH ); - year = RTC_READ( RTC_YEAR ); - wday = RTC_READ( RTC_DAY_OF_WEEK ); - } - else { - RTC_WRITE( RTC_SECONDS, sec ); - RTC_WRITE( RTC_MINUTES, min ); - RTC_WRITE( RTC_HOURS, hour + pm); - RTC_WRITE( RTC_DAY_OF_MONTH, day ); - RTC_WRITE( RTC_MONTH, mon ); - RTC_WRITE( RTC_YEAR, year ); - if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); - } - RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); - restore_flags(flags); - - if (!op) { - /* read: adjust values */ - - if (hour & 0x80) { - hour &= ~0x80; - pm = 1; - } - - if (!(ctrl & RTC_DM_BINARY)) { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - BCD_TO_BIN(wday); - } - - if (!(ctrl & RTC_24H)) { - if (!pm && hour == 12) - hour = 0; - else if (pm && hour != 12) - hour += 12; - } - - t->sec = sec; - t->min = min; - t->hour = hour; - t->day = day; - t->mon = mon - 1; - t->year = year + ((tos_version < 0x306) ? 70 : 68); - t->wday = wday - 1; - } - - return( 0 ); -} - - -static int atari_mste_set_clock_mmss (unsigned long nowtime) -{ - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; - struct MSTE_RTC val; - unsigned char rtc_minutes; - - mste_read(&val); - rtc_minutes= val.min_ones + val.min_tens * 10; - if ((rtc_minutes < real_minutes - ? real_minutes - rtc_minutes - : rtc_minutes - real_minutes) < 30) - { - val.sec_ones = real_seconds % 10; - val.sec_tens = real_seconds / 10; - val.min_ones = real_minutes % 10; - val.min_tens = real_minutes / 10; - mste_write(&val); - } - else - return -1; - return 0; -} - -static int atari_set_clock_mmss (unsigned long nowtime) -{ - int retval = 0; - short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; - unsigned char save_control, save_freq_select, rtc_minutes; - - save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ - RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); - - save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ - RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); - - rtc_minutes = RTC_READ (RTC_MINUTES); - if (!(save_control & RTC_DM_BINARY)) - BCD_TO_BIN (rtc_minutes); - - /* Since we're only adjusting minutes and seconds, don't interfere - with hour overflow. This avoids messing with unknown time zones - but requires your RTC not to be off by more than 30 minutes. */ - if ((rtc_minutes < real_minutes - ? real_minutes - rtc_minutes - : rtc_minutes - real_minutes) < 30) - { - if (!(save_control & RTC_DM_BINARY)) - { - BIN_TO_BCD (real_seconds); - BIN_TO_BCD (real_minutes); - } - RTC_WRITE (RTC_SECONDS, real_seconds); - RTC_WRITE (RTC_MINUTES, real_minutes); - } - else - retval = -1; - - RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); - RTC_WRITE (RTC_CONTROL, save_control); - return retval; -} - -static inline void ata_mfp_out (char c) -{ - while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ - barrier (); - mfp.usart_dta = c; -} - -static void atari_mfp_console_write (const char *str, unsigned int count) -{ - while (count--) { - if (*str == '\n') - ata_mfp_out( '\r' ); - ata_mfp_out( *str++ ); - } -} - -static inline void ata_scc_out (char c) -{ - do { - MFPDELAY(); - } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ - MFPDELAY(); - scc.cha_b_data = c; -} - -static void atari_scc_console_write (const char *str, unsigned int count) -{ - while (count--) { - if (*str == '\n') - ata_scc_out( '\r' ); - ata_scc_out( *str++ ); - } -} - -static int ata_par_out (char c) -{ - extern unsigned long loops_per_sec; - unsigned char tmp; - /* This a some-seconds timeout in case no printer is connected */ - unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000; - - while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ - ; - if (!i) return( 0 ); - - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = c; /* put char onto port */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ + sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ tmp = sound_ym.rd_data_reg_sel; - sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ - MFPDELAY(); /* wait a bit */ - sound_ym.wd_data = tmp | 0x20; /* set strobe H */ - return( 1 ); -} - -static void atari_par_console_write (const char *str, unsigned int count) -{ - static int printer_present = 1; - - if (!printer_present) - return; - - while (count--) { - if (*str == '\n') - if (!ata_par_out( '\r' )) { - printer_present = 0; - return; - } - if (!ata_par_out( *str++ )) { - printer_present = 0; - return; - } - } + sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); + restore_flags(flags); } - - -__initfunc(static void atari_debug_init(void)) -{ -#ifdef CONFIG_KGDB - /* if the m68k_debug_device is used by the GDB stub, do nothing here */ - if (kgdb_initialized) - return(NULL); #endif - if (!strcmp( m68k_debug_device, "ser" )) { - /* defaults to ser2 for a Falcon and ser1 otherwise */ - strcpy( m68k_debug_device, - ((atari_mch_cookie >> 16) == ATARI_MCH_FALCON) ? - "ser2" : "ser1" ); - - } - - if (!strcmp( m68k_debug_device, "ser1" )) { - /* ST-MFP Modem1 serial port */ - mfp.trn_stat &= ~0x01; /* disable TX */ - mfp.usart_ctr = 0x88; /* clk 1:16, 8N1 */ - mfp.tim_ct_cd &= 0x70; /* stop timer D */ - mfp.tim_dt_d = 2; /* 9600 bps */ - mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ - mfp.trn_stat |= 0x01; /* enable TX */ - atari_console_driver.write = atari_mfp_console_write; - } - else if (!strcmp( m68k_debug_device, "ser2" )) { - /* SCC Modem2 serial port */ - static unsigned char *p, scc_table[] = { - 9, 12, /* Reset */ - 4, 0x44, /* x16, 1 stopbit, no parity */ - 3, 0xc0, /* receiver: 8 bpc */ - 5, 0xe2, /* transmitter: 8 bpc, assert dtr/rts */ - 9, 0, /* no interrupts */ - 10, 0, /* NRZ */ - 11, 0x50, /* use baud rate generator */ - 12, 24, 13, 0, /* 9600 baud */ - 14, 2, 14, 3, /* use master clock for BRG, enable */ - 3, 0xc1, /* enable receiver */ - 5, 0xea, /* enable transmitter */ - 0 - }; - - (void)scc.cha_b_ctrl; /* reset reg pointer */ - for( p = scc_table; *p != 0; ) { - scc.cha_b_ctrl = *p++; - MFPDELAY(); - scc.cha_b_ctrl = *p++; - MFPDELAY(); - } - atari_console_driver.write = atari_scc_console_write; - } - else if (!strcmp( m68k_debug_device, "par" )) { - /* parallel printer */ - atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ - sound_ym.rd_data_reg_sel = 7; /* select mixer control */ - sound_ym.wd_data = 0xff; /* sound off, ports are output */ - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = 0; /* no char */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ - sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ - atari_console_driver.write = atari_par_console_write; - } - if (atari_console_driver.write) - register_console(&atari_console_driver); -} - /* ++roman: * * This function does a reset on machines that lack the ability to @@ -1082,11 +645,16 @@ /* On the Medusa, phys. 0x4 may contain garbage because it's no ROM. See above for explanation why we cannot use PTOV(4). */ - reset_addr = is_hades ? 0x7fe00030 : - (is_medusa ? 0xe00030 : *(unsigned long *) 0xff000004); - - acia.key_ctrl = ACIA_RESET; /* reset ACIA for switch off OverScan, if it's active */ - + reset_addr = MACH_IS_HADES ? 0x7fe00030 : + MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : + *(unsigned long *) 0xff000004; + + /* reset ACIA for switch off OverScan, if it's active */ + if (atari_switches & ATARI_SWITCH_OVSC_IKBD) + acia.key_ctrl = ACIA_RESET; + if (atari_switches & ATARI_SWITCH_OVSC_MIDI) + acia.mid_ctrl = ACIA_RESET; + /* processor independent: turn off interrupts and reset the VBR; * the caches must be left enabled, else prefetching the final jump * instruction doesn't work. */ @@ -1126,8 +694,21 @@ "nop\n\t" ".chip 68040\n\t" "cinva %%bc\n\t" + "nop\n\t" "pflusha\n\t" + "nop\n\t" "movec %%d0,%%tc\n\t" + "nop\n\t" + /* the following setup of transparent translations is needed on the + * Afterburner040 to successfully reboot. Other machines shouldn't + * care about a different tt regs setup, they also didn't care in + * the past that the regs weren't turned off. */ + "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */ + "movec %%d0,%%itt0\n\t" + "movec %%d0,%%itt1\n\t" + "orw #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */ + "movec %%d0,%%dtt0\n\t" + "movec %%d0,%%dtt1\n\t" ".chip 68k\n\t" "jmp %0@" : /* no outputs */ @@ -1154,22 +735,24 @@ strcat (model, "ST"); break; case ATARI_MCH_STE: - if ((atari_mch_cookie & 0xffff) == 0x10) + if (MACH_IS_MSTE) strcat (model, "Mega STE"); else strcat (model, "STE"); break; case ATARI_MCH_TT: - if (is_medusa) + if (MACH_IS_MEDUSA) /* Medusa has TT _MCH cookie */ strcat (model, "Medusa"); - else if (is_hades) + else if (MACH_IS_HADES) strcat(model, "Hades"); else strcat (model, "TT"); break; case ATARI_MCH_FALCON: strcat (model, "Falcon"); + if (MACH_IS_AB40) + strcat (model, " (with Afterburner040)"); break; default: sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)", @@ -1225,3 +808,10 @@ return(len); } + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -ur --new-file old/linux/arch/m68k/atari/debug.c new/linux/arch/m68k/atari/debug.c --- old/linux/arch/m68k/atari/debug.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/atari/debug.c Fri Feb 13 01:30:12 1998 @@ -0,0 +1,359 @@ +/* + * linux/arch/m68k/atari/debug.c + * + * Atari debugging and serial console stuff + * + * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +extern char m68k_debug_device[]; + +/* Flag that Modem1 port is already initialized and used */ +int atari_MFP_init_done = 0; +/* Flag that Modem1 port is already initialized and used */ +int atari_SCC_init_done = 0; +/* Can be set somewhere, if a SCC master reset has already be done and should + * not be repeated; used by kgdb */ +int atari_SCC_reset_done = 0; + +static struct console atari_console_driver = { + "debug", + NULL, /* write */ + NULL, /* read */ + NULL, /* device */ + NULL, /* wait_key */ + NULL, /* unblank */ + NULL, /* setup */ + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + + +static inline void ata_mfp_out (char c) +{ + while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ + barrier (); + mfp.usart_dta = c; +} + +void atari_mfp_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + ata_mfp_out( '\r' ); + ata_mfp_out( *str++ ); + } +} + +static inline void ata_scc_out (char c) +{ + do { + MFPDELAY(); + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + MFPDELAY(); + scc.cha_b_data = c; +} + +void atari_scc_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + ata_scc_out( '\r' ); + ata_scc_out( *str++ ); + } +} + +static inline void ata_midi_out (char c) +{ + while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ + barrier (); + acia.mid_data = c; +} + +void atari_midi_console_write (struct console *co, const char *str, + unsigned int count) +{ + while (count--) { + if (*str == '\n') + ata_midi_out( '\r' ); + ata_midi_out( *str++ ); + } +} + +static int ata_par_out (char c) +{ + unsigned char tmp; + /* This a some-seconds timeout in case no printer is connected */ + unsigned long i = loops_per_sec > 1 ? loops_per_sec : 10000000; + + while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ + ; + if (!i) return( 0 ); + + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = c; /* put char onto port */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ + MFPDELAY(); /* wait a bit */ + sound_ym.wd_data = tmp | 0x20; /* set strobe H */ + return( 1 ); +} + +static void atari_par_console_write (struct console *co, const char *str, + unsigned int count) +{ + static int printer_present = 1; + + if (!printer_present) + return; + + while (count--) { + if (*str == '\n') + if (!ata_par_out( '\r' )) { + printer_present = 0; + return; + } + if (!ata_par_out( *str++ )) { + printer_present = 0; + return; + } + } +} + +#ifdef CONFIG_SERIAL_CONSOLE +int atari_mfp_console_wait_key(struct console *co) +{ + while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */ + barrier(); + return( mfp.usart_dta ); +} + +int atari_scc_console_wait_key(struct console *co) +{ + do { + MFPDELAY(); + } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ + MFPDELAY(); + return( scc.cha_b_data ); +} + +int atari_midi_console_wait_key(struct console *co) +{ + while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */ + barrier(); + return( acia.mid_data ); +} +#endif + +/* The following two functions do a quick'n'dirty initialization of the MFP or + * SCC serial ports. They're used by the debugging interface, kgdb, and the + * serial console code. */ +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void atari_init_mfp_port( int cflag )) +#else +void atari_init_mfp_port( int cflag ) +#endif +{ + /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 + * bps, resp., and work only correct if there's a RSVE or RSSPEED */ + static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; + int baud = cflag & CBAUD; + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; + int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* baud_table[] starts at 1200bps */ + + mfp.trn_stat &= ~0x01; /* disable TX */ + mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ + mfp.tim_ct_cd &= 0x70; /* stop timer D */ + mfp.tim_dt_d = baud_table[baud]; + mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ + mfp.trn_stat |= 0x01; /* enable TX */ + + atari_MFP_init_done = 1; +} + +#define SCC_WRITE(reg,val) \ + do { \ + scc.cha_b_ctrl = (reg); \ + MFPDELAY(); \ + scc.cha_b_ctrl = (val); \ + MFPDELAY(); \ + } while(0) + +/* loops_per_sec isn't initialized yet, so we can't use udelay(). This does a + * delay of ~ 60us. */ +#define LONG_DELAY() \ + do { \ + int i; \ + for( i = 100; i > 0; --i ) \ + MFPDELAY(); \ + } while(0) + +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void atari_init_scc_port( int cflag )) +#else +void atari_init_scc_port( int cflag ) +#endif +{ + extern int atari_SCC_reset_done; + static int clksrc_table[9] = + /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ + { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; + static int brgsrc_table[9] = + /* reg 14: 0 = RTxC, 2 = PCLK */ + { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; + static int clkmode_table[9] = + /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; + static int div_table[9] = + /* reg12 (BRG low) */ + { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; + + int baud = cflag & CBAUD; + int clksrc, clkmode, div, reg3, reg5; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* tables starts at 1200bps */ + + clksrc = clksrc_table[baud]; + clkmode = clkmode_table[baud]; + div = div_table[baud]; + if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { + /* special treatment for TT, where rates >= 38400 are done via TRxC */ + clksrc = 0x28; /* TRxC */ + clkmode = baud == 6 ? 0xc0 : + baud == 7 ? 0x80 : /* really 76800bps */ + 0x40; /* really 153600bps */ + div = 0; + } + + reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; + reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; + + (void)scc.cha_b_ctrl; /* reset reg pointer */ + SCC_WRITE( 9, 0xc0 ); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | + clkmode ); + SCC_WRITE( 3, reg3 ); + SCC_WRITE( 5, reg5 ); + SCC_WRITE( 9, 0 ); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 10, 0 ); /* NRZ mode */ + SCC_WRITE( 11, clksrc ); /* main clock source */ + SCC_WRITE( 12, div ); /* BRG value */ + SCC_WRITE( 13, 0 ); /* BRG high byte */ + SCC_WRITE( 14, brgsrc_table[baud] ); + SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); + SCC_WRITE( 3, reg3 | 1 ); + SCC_WRITE( 5, reg5 | 8 ); + + atari_SCC_reset_done = 1; + atari_SCC_init_done = 1; +} + +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void atari_init_midi_port( int cflag )) +#else +void atari_init_midi_port( int cflag ) +#endif +{ + int baud = cflag & CBAUD; + int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; + /* warning 7N1 isn't possible! (instead 7O2 is used...) */ + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; + int div; + + /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as + * default) the standard MIDI speed 31250. */ + if (cflag & CBAUDEX) + baud += B38400; + if (baud == B4800) + div = ACIA_DIV64; /* really 7812.5 bps */ + else if (baud == B38400+2 /* 115200 */) + div = ACIA_DIV1; /* really 500 kbps (does that work??) */ + else + div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ + + /* RTS low, ints disabled */ + acia.mid_ctrl = div | csize | parity | + ((atari_switches & ATARI_SWITCH_MIDI) ? + ACIA_RHTID : ACIA_RLTID); +} + +__initfunc(void atari_debug_init(void)) +{ +#ifdef CONFIG_KGDB + /* the m68k_debug_device is used by the GDB stub, do nothing here */ + return; +#endif + if (!strcmp( m68k_debug_device, "ser" )) { + /* defaults to ser2 for a Falcon and ser1 otherwise */ + strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" ); + + } + + if (!strcmp( m68k_debug_device, "ser1" )) { + /* ST-MFP Modem1 serial port */ + atari_init_mfp_port( B9600|CS8 ); + atari_console_driver.write = atari_mfp_console_write; + } + else if (!strcmp( m68k_debug_device, "ser2" )) { + /* SCC Modem2 serial port */ + atari_init_scc_port( B9600|CS8 ); + atari_console_driver.write = atari_scc_console_write; + } + else if (!strcmp( m68k_debug_device, "midi" )) { + /* MIDI port */ + atari_init_midi_port( B9600|CS8 ); + atari_console_driver.write = atari_midi_console_write; + } + else if (!strcmp( m68k_debug_device, "par" )) { + /* parallel printer */ + atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ + sound_ym.rd_data_reg_sel = 7; /* select mixer control */ + sound_ym.wd_data = 0xff; /* sound off, ports are output */ + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = 0; /* no char */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ + atari_console_driver.write = atari_par_console_write; + } + if (atari_console_driver.write) + register_console(&atari_console_driver); +} + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -ur --new-file old/linux/arch/m68k/atari/joystick.c new/linux/arch/m68k/atari/joystick.c --- old/linux/arch/m68k/atari/joystick.c Wed May 14 07:41:02 1997 +++ new/linux/arch/m68k/atari/joystick.c Fri Feb 27 18:10:33 1998 @@ -82,15 +82,16 @@ return 0; } -static long write_joystick(struct inode *inode, struct file *file, - const char *buffer, unsigned long count) +static ssize_t write_joystick(struct file *file, const char *buffer, + size_t count, loff_t *ppos) { return -EINVAL; } -static long read_joystick(struct inode *inode, struct file *file, - char *buffer, unsigned long count) +static ssize_t read_joystick(struct file *file, char *buffer, size_t count, + loff_t *ppos) { + struct inode *inode = file->f_dentry->d_inode; int minor = DEVICE_NR(inode->i_rdev); if (count < 2) @@ -109,9 +110,9 @@ static unsigned int joystick_poll(struct file *file, poll_table *wait) { - int minor = DEVICE_NR(file->f_inode->i_rdev); + int minor = DEVICE_NR(file->f_dentry->d_inode->i_rdev); - poll_wait(&joystick[minor].wait, wait); + poll_wait(file, &joystick[minor].wait, wait); if (joystick[minor].ready) return POLLIN | POLLRDNORM; return 0; diff -ur --new-file old/linux/arch/m68k/atari/stdma.c new/linux/arch/m68k/atari/stdma.c --- old/linux/arch/m68k/atari/stdma.c Wed May 14 07:41:02 1997 +++ new/linux/arch/m68k/atari/stdma.c Fri Feb 13 01:30:12 1998 @@ -1,6 +1,5 @@ - /* - * linux/atari/stmda.c + * linux/arch/m68k/atari/stmda.c * * Copyright (C) 1994 Roman Hodek * @@ -37,7 +36,6 @@ #include #include #include -#include #include #include diff -ur --new-file old/linux/arch/m68k/atari/stram.c new/linux/arch/m68k/atari/stram.c --- old/linux/arch/m68k/atari/stram.c Wed May 14 07:41:02 1997 +++ new/linux/arch/m68k/atari/stram.c Fri Feb 13 01:30:12 1998 @@ -1,157 +1,56 @@ +/* + * arch/m68k/atari/stram.c: Functions for ST-RAM allocations + * + * Copyright 1994-97 Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +#include #include #include #include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include #include #include +#include +#include -#if 0 - -struct stram_desc - { - unsigned first:1; - unsigned last:1; - unsigned alloced:1; - unsigned length:24; - }; - -#define DP(ptr) ((struct stram_desc *) (ptr)) - -static unsigned long stramsize; -static unsigned long stramaddr; - -void -atari_stram_init (void) -{ - struct stram_desc *dp; - stramaddr = atari_stram_start; - stramsize = atari_stram_size; - - /* initialize start boundary */ - dp = DP (stramaddr); - dp->first = 1; - dp->alloced = 0; - dp->length = stramsize - 2 * sizeof (*dp); - - /* initialize end boundary */ - dp = DP (stramaddr + stramsize) - 1; - dp->last = 1; - dp->alloced = 0; - dp->length = stramsize - 2 * sizeof (*dp); - -#ifdef DEBUG - printk ("stram end boundary is %p, length is %d\n", dp, - dp->length); -#endif -} - -void * -atari_stram_alloc (long size) -{ - /* last chunk */ - struct stram_desc *dp; - void *ptr; - - /* round off */ - size = (size + 3) & ~3; -#ifdef DEBUG - printk ("stram_alloc: allocate %ld bytes\n", size); +#ifdef CONFIG_STRAM_SWAP +#define MAJOR_NR Z2RAM_MAJOR +#include +#undef DEVICE_NAME +#define DEVICE_NAME "stram" #endif - /* - * get pointer to descriptor for last chunk by - * going backwards from end chunk - */ - dp = DP (stramaddr + stramsize) - 1; - dp = DP ((unsigned long) dp - dp->length) - 1; - - while ((dp->alloced || dp->length < size) && !dp->first) - dp = DP ((unsigned long) dp - dp[-1].length) - 2; - - if (dp->alloced || dp->length < size) - { - printk ("no stram available for %ld allocation\n", size); - return NULL; - } - - if (dp->length < size + 2 * sizeof (*dp)) - { - /* length too small to split; allocate the whole thing */ - dp->alloced = 1; - ptr = (void *) (dp + 1); - dp = DP ((unsigned long) ptr + dp->length); - dp->alloced = 1; -#ifdef DEBUG - printk ("stram_alloc: no split\n"); -#endif - } - else - { - /* split the extent; use the end part */ - long newsize = dp->length - (2 * sizeof (*dp) + size); +#undef DEBUG #ifdef DEBUG - printk ("stram_alloc: splitting %d to %ld\n", dp->length, - newsize); +#define DPRINTK(fmt,args...) printk( fmt, ##args ) +#else +#define DPRINTK(fmt,args...) #endif - dp->length = newsize; - dp = DP ((unsigned long) (dp + 1) + newsize); - dp->first = dp->last = 0; - dp->alloced = 0; - dp->length = newsize; - dp++; - dp->first = dp->last = 0; - dp->alloced = 1; - dp->length = size; - ptr = (void *) (dp + 1); - dp = DP ((unsigned long) ptr + size); - dp->alloced = 1; - dp->length = size; - } -#ifdef DEBUG - printk ("stram_alloc: returning %p\n", ptr); +#if defined(CONFIG_PROC_FS) && defined(CONFIG_STRAM_PROC) +/* abbrev for the && above... */ +#define DO_PROC +#include #endif - return ptr; -} - -void -atari_stram_free (void *ptr) -{ - struct stram_desc *sdp = DP (ptr) - 1, *dp2; - struct stram_desc *edp = DP ((unsigned long) ptr + sdp->length); - - /* deallocate the chunk */ - sdp->alloced = edp->alloced = 0; - /* check if we should merge with the previous chunk */ - if (!sdp->first && !sdp[-1].alloced) - { - dp2 = DP ((unsigned long) sdp - sdp[-1].length) - 2; - dp2->length += sdp->length + 2 * sizeof (*sdp); - edp->length = dp2->length; - sdp = dp2; - } - - /* check if we should merge with the following chunk */ - if (!edp->last && !edp[1].alloced) - { - dp2 = DP ((unsigned long) edp + edp[1].length) + 2; - dp2->length += edp->length + 2 * sizeof (*sdp); - sdp->length = dp2->length; - edp = dp2; - } -} - -#else - -#include -#include - -/* ++roman: +/* Pre-swapping comments: + * + * ++roman: * * New version of ST-Ram buffer allocation. Instead of using the * 1 MB - 4 KB that remain when the the ST-Ram chunk starts at $1000 @@ -173,72 +72,1414 @@ * no provision now for freeing ST-Ram buffers. It seems that isn't * really needed. * - * ToDo: - * Check the high level scsi code what is done when the - * UNCHECKED_ISA_DMA flag is set. It guess, it is just a test for adr - * < 16 Mega. There should be call to atari_stram_alloc() instead. - * - * Also ToDo: - * Go through head.S and delete parts no longer needed (transparent - * mapping of ST-Ram etc.) + */ + +/* + * New Nov 1997: Use ST-RAM as swap space! + * + * In the past, there were often problems with modules that require ST-RAM + * buffers. Such drivers have to use __get_dma_pages(), which unfortunately + * often isn't very successful in allocating more than 1 page :-( [1] The net + * result was that most of the time you couldn't insmod such modules (ataflop, + * ACSI, SCSI on Falcon, Atari internal framebuffer, not to speak of acsi_slm, + * which needs a 1 MB buffer... :-). + * + * To overcome this limitation, ST-RAM can now be turned into a very + * high-speed swap space. If a request for an ST-RAM buffer comes, the kernel + * now tries to unswap some pages on that swap device to make some free (and + * contiguous) space. This works much better in comparison to + * __get_dma_pages(), since used swap pages can be selectively freed by either + * moving them to somewhere else in swap space, or by reading them back into + * system memory. Ok, there operation of unswapping isn't really cheap (for + * each page, one has to go through the page tables of all processes), but it + * doesn't happen that often (only when allocation ST-RAM, i.e. when loading a + * module that needs ST-RAM). But it at least makes it possible to load such + * modules! + * + * It could also be that overall system performance increases a bit due to + * ST-RAM swapping, since slow ST-RAM isn't used anymore for holding data or + * executing code in. It's then just a (very fast, compared to disk) back + * storage for not-so-often needed data. (But this effect must be compared + * with the loss of total memory...) Don't know if the effect is already + * visible on a TT, where the speed difference between ST- and TT-RAM isn't + * that dramatic, but it should on machines where TT-RAM is really much faster + * (e.g. Afterburner). * + * [1]: __get_free_pages() does a fine job if you only want one page, but if + * you want more (contiguous) pages, it can give you such a block only if + * there's already a free one. The algorithm can't try to free buffers or swap + * out something in order to make more free space, since all that page-freeing + * mechanisms work "target-less", i.e. they just free something, but not in a + * specific place. I.e., __get_free_pages() can't do anything to free + * *adjacent* pages :-( This situation becomes even worse for DMA memory, + * since the freeing algorithms are also blind to DMA capability of pages. + */ + +#ifdef CONFIG_STRAM_SWAP +#define ALIGN_IF_SWAP(x) PAGE_ALIGN(x) +#else +#define ALIGN_IF_SWAP(x) (x) +#endif + +/* map entry for reserved swap page (used as buffer) */ +#define SWP_RSVD 0x80 + +/* get index of swap page at address 'addr' */ +#define SWAP_NR(addr) (((unsigned long)(addr)-swap_start) >> PAGE_SHIFT) + +/* get address of swap page #'nr' */ +#define SWAP_ADDR(nr) ((void *)(swap_start + ((nr)<> PAGE_SHIFT) + +/* The following two numbers define the maximum fraction of ST-RAM in total + * memory, below that the kernel would automatically use ST-RAM as swap + * space. This decision can be overriden with stram_swap= */ +#define MAX_STRAM_FRACTION_NOM 1 +#define MAX_STRAM_FRACTION_DENOM 3 + +/* Start and end of the (pre-mem_init) reserved ST-RAM region */ +static unsigned long rsvd_stram_beg, rsvd_stram_end; + +/* Start and end (virtual) of ST-RAM */ +static unsigned long stram_start, stram_end; + +/* set after memory_init() executed and allocations via start_mem aren't + * possible anymore */ +static int mem_init_done = 0; + +/* set if kernel is in ST-RAM */ +static int kernel_in_stram; + +typedef struct stram_block { + struct stram_block *next; + unsigned long start; + unsigned long size; + unsigned flags; + const char *owner; +} BLOCK; + +/* values for flags field */ +#define BLOCK_FREE 0x01 /* free structure in the BLOCKs pool */ +#define BLOCK_KMALLOCED 0x02 /* structure allocated by kmalloc() */ +#define BLOCK_STATIC 0x04 /* pre-mem_init() allocated block */ +#define BLOCK_GFP 0x08 /* block allocated with __get_dma_pages() */ +#define BLOCK_INSWAP 0x10 /* block allocated in swap space */ + +/* list of allocated blocks */ +static BLOCK *alloc_list = NULL; + +/* We can't always use kmalloc() to allocate BLOCK structures, since + * stram_alloc() can be called rather early. So we need some pool of + * statically allocated structures. 20 of them is more than enough, so in most + * cases we never should need to call kmalloc(). */ +#define N_STATIC_BLOCKS 20 +static BLOCK static_blocks[N_STATIC_BLOCKS]; + +#ifdef CONFIG_STRAM_SWAP +/* max. number of bytes to use for swapping + * 0 = no ST-RAM swapping + * -1 = do swapping (to whole ST-RAM) if it's less than MAX_STRAM_FRACTION of + * total memory */ - +static int max_swap_size = -1; -unsigned long rsvd_stram_beg, rsvd_stram_end; - /* Start and end of the reserved ST-Ram region */ -static unsigned long stram_end; - /* Overall end of ST-Ram */ +/* start and end of swapping area */ +static unsigned long swap_start, swap_end; +/* The ST-RAM's swap info structure */ +static struct swap_info_struct *stram_swap_info; +/* The ST-RAM's swap type */ +static int stram_swap_type; + +/* major and minor device number of the ST-RAM device; for the major, we use + * the same as Amiga z2ram, which is really similar and impossible on Atari, + * and for the minor a relatively odd number to avoid the user creating and + * using that device. */ +#define STRAM_MAJOR Z2RAM_MAJOR +#define STRAM_MINOR 13 + +/* Some impossible pointer value */ +#define MAGIC_FILE_P (struct file *)0xffffdead + +#ifdef DO_PROC +static unsigned stat_swap_read = 0; +static unsigned stat_swap_write = 0; +static unsigned stat_swap_move = 0; +static unsigned stat_swap_force = 0; +#endif /* DO_PROC */ + +#endif /* CONFIG_STRAM_SWAP */ + +/***************************** Prototypes *****************************/ + +#ifdef CONFIG_STRAM_SWAP +static int swap_init( unsigned long start_mem, unsigned long swap_data ); +static inline int unswap_pte( struct vm_area_struct * vma, unsigned long + address, pte_t *dir, unsigned long entry, + unsigned long page, int isswap ); +static inline int unswap_pmd( struct vm_area_struct * vma, pmd_t *dir, + unsigned long address, unsigned long size, + unsigned long offset, unsigned long entry, + unsigned long page, int isswap ); +static inline int unswap_pgd( struct vm_area_struct * vma, pgd_t *dir, + unsigned long address, unsigned long size, + unsigned long entry, unsigned long page, int + isswap ); +static int unswap_vma( struct vm_area_struct * vma, pgd_t *pgdir, unsigned + long entry, unsigned long page, int isswap ); +static int unswap_process( struct mm_struct * mm, unsigned long entry, + unsigned long page, int isswap ); +static int unswap_by_move( unsigned char *map, unsigned long max, unsigned + long start, unsigned long n_pages ); +static int unswap_by_read( unsigned char *map, unsigned long max, unsigned + long start, unsigned long n_pages ); +static void *get_stram_region( unsigned long n_pages ); +static void free_stram_region( unsigned long offset, unsigned long n_pages + ); +static int in_some_region( unsigned long addr ); +static unsigned long find_free_region( unsigned long n_pages, unsigned long + *total_free, unsigned long + *region_free ); +static void do_stram_request( void ); +static int stram_open( struct inode *inode, struct file *filp ); +static int stram_release( struct inode *inode, struct file *filp ); +static void do_z2_request( void ); +#endif +static int get_gfp_order( unsigned long size ); +static void reserve_region( unsigned long addr, unsigned long end ); +static BLOCK *add_region( void *addr, unsigned long size ); +static BLOCK *find_region( void *addr ); +static int remove_region( BLOCK *block ); + +/************************* End of Prototypes **************************/ + + +/* ------------------------------------------------------------------------ */ +/* Public Interface */ +/* ------------------------------------------------------------------------ */ + +/* + * This init function is called very early by atari/config.c + * It initializes some internal variables needed for stram_alloc() + */ __initfunc(void atari_stram_init( void )) +{ + int i; -{ int i; + /* initialize static blocks */ + for( i = 0; i < N_STATIC_BLOCKS; ++i ) + static_blocks[i].flags = BLOCK_FREE; + + /* determine whether kernel code resides in ST-RAM (then ST-RAM is the + * first memory block at virtual 0x0) */ + stram_start = PTOV( 0 ); + kernel_in_stram = (stram_start == 0); for( i = 0; i < m68k_num_memory; ++i ) { if (m68k_memory[i].addr == 0) { - rsvd_stram_beg = PTOV( 0x800 ); /* skip super-only first 2 KB! */ + /* skip first 2kB or page (supervisor-only!) */ + rsvd_stram_beg = stram_start + ALIGN_IF_SWAP(0x800); rsvd_stram_end = rsvd_stram_beg; - stram_end = rsvd_stram_beg - 0x800 + m68k_memory[i].size; + stram_end = stram_start + m68k_memory[i].size; return; } } /* Should never come here! (There is always ST-Ram!) */ + panic( "atari_stram_init: no ST-RAM found!" ); } -void *atari_stram_alloc( long size, unsigned long *start_mem ) +/* + * This function is called from mem_init() to reserve the pages needed for + * ST-RAM management. + */ +__initfunc(void atari_stram_reserve_pages( unsigned long start_mem )) +{ +#ifdef CONFIG_STRAM_SWAP + /* if max_swap_size is negative (i.e. no stram_swap= option given), + * determine at run time whether to use ST-RAM swapping */ + if (max_swap_size < 0) + /* Use swapping if ST-RAM doesn't make up more than MAX_STRAM_FRACTION + * of total memory. In that case, the max. size is set to 16 MB, + * because ST-RAM can never be bigger than that. + * Also, never use swapping on a Hades, there's no separate ST-RAM in + * that machine. */ + max_swap_size = + (!MACH_IS_HADES && + (N_PAGES(stram_end-stram_start)*MAX_STRAM_FRACTION_DENOM <= + max_mapnr*MAX_STRAM_FRACTION_NOM)) ? 16*1024*1024 : 0; + DPRINTK( "atari_stram_reserve_pages: max_swap_size = %d\n", max_swap_size ); +#endif + /* always reserve first page of ST-RAM, the first 2 kB are + * supervisor-only! */ + set_bit( PG_reserved, &mem_map[MAP_NR(stram_start)].flags ); + +#ifdef CONFIG_STRAM_SWAP + if (!max_swap_size) { + fallback: +#endif + DPRINTK( "atari_stram_reserve_pages: swapping disabled\n" ); + if (!kernel_in_stram) { + /* Reserve all pages that have been marked by pre-mem_init + * stram_alloc() (e.g. for the screen memory). */ + reserve_region( rsvd_stram_beg, rsvd_stram_end ); + DPRINTK( "atari_stram_reserve_pages: reseverved %08lx-%08lx\n", + rsvd_stram_beg, rsvd_stram_end ); + } + /* else (kernel in ST-RAM): nothing to do, ST-RAM buffers are + * kernel data */ +#ifdef CONFIG_STRAM_SWAP + } + else { + unsigned long swap_data; + BLOCK *p; + + /* determine first page to use as swap: + * if the kernel is in TT-RAM, this is the first page of (usable) + * ST-RAM; else if there were already some allocations (probable...), + * use the lowest address of these (the list is sorted by address!); + * otherwise just use the end of kernel data (= start_mem) */ + swap_start = !kernel_in_stram ? stram_start + PAGE_SIZE : + alloc_list ? alloc_list->start : + start_mem; + /* decrement by one page, rest of kernel assumes that first swap page + * is always reserved and maybe doesn't handle SWP_ENTRY == 0 + * correctly */ + swap_start -= PAGE_SIZE; + swap_end = stram_end; + if (swap_end-swap_start > max_swap_size) + swap_end = swap_start + max_swap_size; + DPRINTK( "atari_stram_reserve_pages: swapping enabled; " + "swap=%08lx-%08lx\n", swap_start, swap_end ); + + /* reserve some amount of memory for maintainance of swapping itself: + * 1 page for the lockmap, and one page for each 4096 (PAGE_SIZE) swap + * pages. (1 byte for each page) */ + swap_data = start_mem; + start_mem += PAGE_ALIGN(SWAP_NR(swap_end)) + PAGE_SIZE; + /* correct swap_start if necessary */ + if (swap_start == swap_data) + swap_start = start_mem; + + if (!swap_init( start_mem, swap_data )) { + printk( KERN_ERR "ST-RAM swap space initialization failed\n" ); + max_swap_size = 0; + goto fallback; + } + /* reserve region for swapping meta-data */ + reserve_region( swap_data, start_mem ); + /* reserve swapping area itself */ + reserve_region( swap_start+PAGE_SIZE, swap_end ); + + /* Formerly static areas have been included in the swap area. */ + for( p = alloc_list; p; p = p->next ) { + if (p->flags & BLOCK_STATIC) + p->flags = (p->flags & ~BLOCK_STATIC) | BLOCK_INSWAP; + } + + /* + * If the whole ST-RAM is used for swapping, there are no allocatable + * dma pages left. But unfortunately, some shared parts of the kernel + * (particularily the SCSI mid-level) call __get_dma_pages() + * unconditionally :-( These calls then fail, and scsi.c even doesn't + * check for NULL return values and just crashes. The quick fix for + * this (instead of doing much clean up work in the SCSI code) is to + * pretend all pages are DMA-able by setting mach_max_dma_address to + * ULONG_MAX. This doesn't change any functionality so far, since + * get_dma_pages() shouldn't be used on Atari anyway anymore (better + * use atari_stram_alloc()), and the Atari SCSI drivers don't need DMA + * memory. But unfortunately there's now no kind of warning (even not + * a NULL return value) if you use get_dma_pages() nevertheless :-( + * You just will get non-DMA-able memory... + */ + mach_max_dma_address = 0xffffffff; + + /* + * Ok, num_physpages needs not be really exact, but it's better to + * subtract the pages set aside for swapping. + */ + num_physpages -= SWAP_NR(swap_end)-1; + } +#endif + + mem_init_done = 1; +} + + +/* + * This is main public interface: somehow allocate a ST-RAM block + * There are three strategies: + * + * - If we're before mem_init(), we have to make a static allocation. The + * region is taken in the kernel data area (if the kernel is in ST-RAM) or + * from the start of ST-RAM (if the kernel is in TT-RAM) and added to the + * rsvd_stram_* region. The ST-RAM is somewhere in the middle of kernel + * address space in the latter case. + * + * - If mem_init() already has been called and ST-RAM swapping is enabled, + * try to get the memory from the (pseudo) swap-space, either free already + * or by moving some other pages out of the swap. + * + * - If mem_init() already has been called, and ST-RAM swapping is not + * enabled, the only possibility is to try with __get_dma_pages(). This has + * the disadvantage that it's very hard to get more than 1 page, and it is + * likely to fail :-( + * + */ +void *atari_stram_alloc( long size, unsigned long *start_mem, + const char *owner ) { - static int kernel_in_stram = -1; + void *addr = NULL; + BLOCK *block; + int flags; + + DPRINTK( "atari_stram_alloc(size=%08lx,*start_mem=%08lx,owner=%s)\n", + size, start_mem ? *start_mem : 0xffffffff, owner ); - void *adr = 0; + if (start_mem && mem_init_done) { + printk( KERN_ERR "atari_stram_alloc called with start_mem!=NULL " + "after mem_init() from %p\n", __builtin_return_address(0) ); + return( NULL ); + } + if (!start_mem && !mem_init_done) { + printk( KERN_ERR "atari_stram_alloc called with start_mem==NULL " + "before mem_init() from %p\n", __builtin_return_address(0) ); + return( NULL ); + } + + size = ALIGN_IF_SWAP(size); + DPRINTK( "atari_stram_alloc: rounded size = %08lx\n", size ); + if (!mem_init_done) { + /* before mem_init(): allocate "statically", i.e. either in the kernel + * data space (current end in *start_mem), or at the end of currently + * reserved ST-RAM. */ + if (kernel_in_stram) { + /* Get memory from kernel data space */ + *start_mem = ALIGN_IF_SWAP(*start_mem); + addr = (void *)*start_mem; + *start_mem += size; + DPRINTK( "atari_stram_alloc: pre-mem_init and k/ST: " + "shifted start_mem to %08lx, addr=%p\n", + *start_mem, addr ); + } + else { + /* Get memory from rsvd_stram_beg */ + if (rsvd_stram_end + size < stram_end) { + addr = (void *) rsvd_stram_end; + rsvd_stram_end += size; + DPRINTK( "atari_stram_alloc: pre-mem_init and k/TT: " + "shifted rsvd_stram_end to %08lx, addr=%p\n", + rsvd_stram_end, addr ); + } + } + flags = BLOCK_STATIC; + } +#ifdef CONFIG_STRAM_SWAP + else if (max_swap_size) { + /* If swapping is active (can only be the case after mem_init()!): + * make some free space in the swap "device". */ + DPRINTK( "atari_stram_alloc: after mem_init, swapping ok, " + "calling get_region\n" ); + addr = get_stram_region( N_PAGES(size) ); + flags = BLOCK_INSWAP; + } +#endif + else { + /* After mem_init() and no swapping: can only resort to + * __get_dma_pages() */ + addr = (void *)__get_dma_pages(GFP_KERNEL, get_gfp_order(size)); + flags = BLOCK_GFP; + DPRINTK( "atari_stram_alloc: after mem_init, swapping off, " + "get_pages=%p\n", addr ); + } + + if (addr) { + if (!(block = add_region( addr, size ))) { + /* out of memory for BLOCK structure :-( */ + DPRINTK( "atari_stram_alloc: out of mem for BLOCK -- " + "freeing again\n" ); + if (flags == BLOCK_STATIC) + rsvd_stram_end -= size; +#ifdef CONFIG_STRAM_SWAP + else if (flags == BLOCK_INSWAP) + free_stram_region( SWAP_NR(addr), N_PAGES(size) ); +#endif + else + free_pages( (unsigned long)addr, get_gfp_order(size)); + return( NULL ); + } + block->owner = owner; + block->flags |= flags; + } + return( addr ); +} + +void atari_stram_free( void *addr ) + +{ + BLOCK *block; + + DPRINTK( "atari_stram_free(addr=%p)\n", addr ); + + if (!(block = find_region( addr ))) { + printk( KERN_ERR "Attempt to free non-allocated ST-RAM block at %p " + "from %p\n", addr, __builtin_return_address(0) ); + return; + } + DPRINTK( "atari_stram_free: found block (%p): size=%08lx, owner=%s, " + "flags=%02x\n", block, block->size, block->owner, block->flags ); - if (kernel_in_stram < 0) - kernel_in_stram = (PTOV( 0 ) == 0); +#ifdef CONFIG_STRAM_SWAP + if (!max_swap_size) { +#endif + if (block->flags & BLOCK_GFP) { + DPRINTK( "atari_stram_free: is kmalloced, order_size=%d\n", + get_gfp_order(block->size) ); + free_pages( (unsigned long)addr, get_gfp_order(block->size) ); + } + else + goto fail; +#ifdef CONFIG_STRAM_SWAP + } + else if (block->flags & (BLOCK_INSWAP|BLOCK_STATIC)) { + DPRINTK( "atari_stram_free: is swap-alloced\n" ); + free_stram_region( SWAP_NR(block->start), N_PAGES(block->size) ); + } + else + goto fail; +#endif + remove_region( block ); + return; + + fail: + printk( KERN_ERR "atari_stram_free: cannot free block at %p " + "(called from %p)\n", addr, __builtin_return_address(0) ); +} + + +#ifdef CONFIG_STRAM_SWAP + + +/* ------------------------------------------------------------------------ */ +/* Main Swapping Functions */ +/* ------------------------------------------------------------------------ */ - if (kernel_in_stram) { - /* Get memory from kernel data space */ - adr = (void *) *start_mem; - *start_mem += size; + +/* + * Initialize ST-RAM swap device + * (lots copied and modified from sys_swapon() in mm/swapfile.c) + */ +__initfunc(static int swap_init( unsigned long start_mem, + unsigned long swap_data )) +{ + static struct dentry fake_dentry[3]; + struct swap_info_struct *p; + struct inode swap_inode; + unsigned int type; + unsigned long addr; + int i, j, k, prev; + + DPRINTK( "swap_init(start_mem=%08lx, swap_data=%08lx)\n", + start_mem, swap_data ); + + /* need at least one page for swapping to (and this also isn't very + * much... :-) */ + if (swap_end - swap_start < 2*PAGE_SIZE) { + printk( KERN_WARNING "stram_swap_init: swap space too small\n" ); + return( 0 ); + } + + /* find free slot in swap_info */ + for( p = swap_info, type = 0; type < nr_swapfiles; type++, p++ ) + if (!(p->flags & SWP_USED)) + break; + if (type >= MAX_SWAPFILES) { + printk( KERN_WARNING "stram_swap_init: max. number of " + "swap devices exhausted\n" ); + return( 0 ); + } + if (type >= nr_swapfiles) + nr_swapfiles = type+1; + + stram_swap_info = p; + stram_swap_type = type; + + /* fake some dir cache entries to give us some name in /dev/swaps */ + fake_dentry[0].d_covers = &fake_dentry[1]; + fake_dentry[0].d_parent = &fake_dentry[0]; + fake_dentry[1].d_parent = &fake_dentry[2]; + fake_dentry[1].d_name.name = "stram (internal)"; + fake_dentry[1].d_name.len = 16; + fake_dentry[2].d_covers = &fake_dentry[2]; + fake_dentry[2].d_parent = &fake_dentry[2]; + + p->flags = SWP_USED; + p->swap_file = &fake_dentry[0]; + p->swap_device = 0; + p->swap_lockmap = (unsigned char *)(swap_data); + p->swap_map = (unsigned char *)(swap_data + PAGE_SIZE); + p->cluster_nr = 0; + p->next = -1; + p->prio = 0x7ff0; /* a rather high priority, but not the higest + * to give the user a chance to override */ + + /* call stram_open() directly, avoids at least the overhead in + * constructing a dummy file structure... */ + p->swap_device = MKDEV( STRAM_MAJOR, STRAM_MINOR ); + swap_inode.i_rdev = p->swap_device; + stram_open( &swap_inode, MAGIC_FILE_P ); + p->max = SWAP_NR(swap_end); + + /* initialize lockmap */ + memset( p->swap_lockmap, 0, PAGE_SIZE ); + + /* initialize swap_map: set regions that are already allocated or belong + * to kernel data space to SWP_RSVD, otherwise to free */ + j = 0; /* # of free pages */ + k = 0; /* # of already allocated pages (from pre-mem_init stram_alloc()) */ + p->lowest_bit = 0; + p->highest_bit = 0; + for( i = 1, addr = (unsigned long)SWAP_ADDR(1); i < p->max; + i++, addr += PAGE_SIZE ) { + if (in_some_region( addr )) { + p->swap_map[i] = SWP_RSVD; + ++k; + } + else if (kernel_in_stram && addr < start_mem ) { + p->swap_map[i] = SWP_RSVD; + } + else { + p->swap_map[i] = 0; + ++j; + if (!p->lowest_bit) p->lowest_bit = i; + p->highest_bit = i; + } + } + /* first page always reserved (and doesn't really belong to swap space) */ + p->swap_map[0] = SWP_RSVD; + + /* now swapping to this device ok */ + p->pages = j + k; + nr_swap_pages += j; + p->flags = SWP_WRITEOK; + + /* insert swap space into swap_list */ + prev = -1; + for (i = swap_list.head; i >= 0; i = swap_info[i].next) { + if (p->prio >= swap_info[i].prio) { + break; + } + prev = i; + } + p->next = i; + if (prev < 0) { + swap_list.head = swap_list.next = p - swap_info; + } else { + swap_info[prev].next = p - swap_info; + } + + printk( KERN_INFO "Using %dk (%d pages) of ST-RAM as swap space.\n", + p->pages << 2, p->pages ); + return( 1 ); +} + + +/* + * The swap entry has been read in advance, and we return 1 to indicate + * that the page has been used or is no longer needed. + */ +static inline int unswap_pte( struct vm_area_struct * vma, unsigned long + address, pte_t *dir, unsigned long entry, + unsigned long page, int isswap ) +{ + pte_t pte = *dir; + + if (pte_none(pte)) + return 0; + if (pte_present(pte)) { + struct page *pg; + unsigned long page_nr = MAP_NR(pte_page(pte)); + unsigned long pg_swap_entry; + + if (page_nr >= max_mapnr) + return 0; + pg = mem_map + page_nr; + if (!(pg_swap_entry = in_swap_cache(pg))) + return 0; + if (pg_swap_entry != entry) + return 0; + if (isswap) { + DPRINTK( "unswap_pte: page %08lx = entry %08lx was in swap cache; " + "exchanging to %08lx\n", + page_address(pg), entry, page ); + pg->offset = page; + swap_free(entry); + return 1; + } + else { + DPRINTK( "unswap_pte: page %08lx = entry %08lx was in swap cache; " + "deleted there\n", page_address(pg), entry ); + delete_from_swap_cache(pg); + set_pte(dir, pte_mkdirty(pte)); + free_page(page); + return 1; + } + } + if (pte_val(pte) != entry) + return 0; + + if (isswap) { + DPRINTK( "unswap_pte: replacing entry %08lx by %08lx", entry, page ); + set_pte(dir, __pte(page)); } else { - /* Get memory from rsvd_stram_beg */ - if (rsvd_stram_end + size < stram_end) { - adr = (void *) rsvd_stram_end; - rsvd_stram_end += size; + DPRINTK( "unswap_pte: replacing entry %08lx by new page %08lx", + entry, page ); + set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page,vma->vm_page_prot)))); + ++vma->vm_mm->rss; + } + swap_free(entry); + return 1; +} + +static inline int unswap_pmd( struct vm_area_struct * vma, pmd_t *dir, + unsigned long address, unsigned long size, + unsigned long offset, unsigned long entry, + unsigned long page, int isswap ) +{ + pte_t * pte; + unsigned long end; + + if (pmd_none(*dir)) + return 0; + if (pmd_bad(*dir)) { + printk("unswap_pmd: bad pmd (%08lx)\n", pmd_val(*dir)); + pmd_clear(dir); + return 0; + } + pte = pte_offset(dir, address); + offset += address & PMD_MASK; + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + if (unswap_pte( vma, offset+address-vma->vm_start, pte, entry, + page, isswap )) + return 1; + address += PAGE_SIZE; + pte++; + } while (address < end); + return 0; +} + +static inline int unswap_pgd( struct vm_area_struct * vma, pgd_t *dir, + unsigned long address, unsigned long size, + unsigned long entry, unsigned long page, + int isswap ) +{ + pmd_t * pmd; + unsigned long offset, end; + + if (pgd_none(*dir)) + return 0; + if (pgd_bad(*dir)) { + printk("unswap_pgd: bad pgd (%08lx)\n", pgd_val(*dir)); + pgd_clear(dir); + return 0; + } + pmd = pmd_offset(dir, address); + offset = address & PGDIR_MASK; + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + do { + if (unswap_pmd( vma, pmd, address, end - address, offset, entry, + page, isswap )) + return 1; + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +static int unswap_vma( struct vm_area_struct * vma, pgd_t *pgdir, + unsigned long entry, unsigned long page, int isswap ) +{ + unsigned long start = vma->vm_start, end = vma->vm_end; + + while( start < end ) { + if (unswap_pgd( vma, pgdir, start, end - start, entry, page, isswap )) + return 1; + start = (start + PGDIR_SIZE) & PGDIR_MASK; + pgdir++; + } + return 0; +} + +static int unswap_process( struct mm_struct * mm, unsigned long entry, + unsigned long page, int isswap ) +{ + struct vm_area_struct* vma; + + /* + * Go through process' page directory. + */ + if (!mm || mm == &init_mm) + return 0; + for( vma = mm->mmap; vma; vma = vma->vm_next ) { + pgd_t * pgd = pgd_offset(mm, vma->vm_start); + if (unswap_vma( vma, pgd, entry, page, isswap )) + return 1; + } + return 0; +} + + +static int unswap_by_move( unsigned char *map, unsigned long max, + unsigned long start, unsigned long n_pages ) +{ + struct task_struct *p; + unsigned long entry, rover = (start == 1) ? n_pages+1 : 1; + unsigned long i, j; + + DPRINTK( "unswapping %lu..%lu by moving in swap\n", + start, start+n_pages-1 ); + + /* can free the allocated pages by moving them to other swap pages */ + for( i = start; i < start+n_pages; ++i ) { + if (!map[i]) { + map[i] = SWP_RSVD; + DPRINTK( "unswap: page %lu was free\n", i ); + continue; + } + else if (map[i] == SWP_RSVD) { + printk( KERN_ERR "get_stram_region: page %lu already " + "reserved??\n", i ); + } + DPRINTK( "unswap: page %lu is alloced, count=%u\n", i, map[i] ); + + /* find a free page not in our region */ + for( j = rover; j != rover-1; j = (j == max-1) ? 1 : j+1 ) { + if (j >= start && j < start+n_pages) + continue; + if (!map[j]) { + rover = j+1; + break; + } + } + if (j == rover-1) { + printk( KERN_ERR "get_stram_region: not enough free swap " + "pages now??\n" ); + return( -ENOMEM ); + } + DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n", + i, map[i], j, map[j], nr_swap_pages ); + + --nr_swap_pages; + entry = SWP_ENTRY( stram_swap_type, j ); + if (stram_swap_info->lowest_bit == j) + stram_swap_info->lowest_bit++; + if (stram_swap_info->highest_bit == j) + stram_swap_info->highest_bit--; + + memcpy( SWAP_ADDR(j), SWAP_ADDR(i), PAGE_SIZE ); +#ifdef DO_PROC + stat_swap_move++; +#endif + + while( map[i] ) { + for_each_task(p) { + if (unswap_process( p->mm, SWP_ENTRY( stram_swap_type, i ), + entry, 1 )) { + map[j]++; + goto repeat; + } + } + if (map[i] && map[i] != 127) { + printk( KERN_ERR "get_stram_region: ST-RAM swap page %lu " + "not used by any process\n", i ); + /* quit while loop and overwrite bad map entry */ + break; + } + else if (!map[i]) { + /* somebody else must have swapped in that page, so free the + * new one (we're moving to) */ + DPRINTK( "unswap: map[i] became 0, also clearing map[j]\n" ); + map[j] = 0; + } + repeat: + } + + DPRINTK( "unswap: map[i=%lu]=%u map[j=%lu]=%u nr_swap=%u\n", + i, map[i], j, map[j], nr_swap_pages ); + map[i] = SWP_RSVD; + if (stram_swap_info->lowest_bit == i) + stram_swap_info->lowest_bit++; + if (stram_swap_info->highest_bit == i) + stram_swap_info->highest_bit--; + --nr_swap_pages; + } + return( 0 ); +} + +static int unswap_by_read( unsigned char *map, unsigned long max, + unsigned long start, unsigned long n_pages ) +{ + struct task_struct *p; + unsigned long entry, page = 0; + unsigned long i; + + DPRINTK( "unswapping %lu..%lu by reading in\n", + start, start+n_pages-1 ); + + for( i = start; i < start+n_pages; ++i ) { + if (map[i] == SWP_RSVD) { + printk( KERN_ERR "get_stram_region: page %lu already " + "reserved??\n", i ); + continue; + } + entry = SWP_ENTRY( stram_swap_type, i ); + DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n", + i, map[i], nr_swap_pages ); + + while( map[i] ) { + if (!page && !(page = __get_free_page(GFP_KERNEL))) { + printk( KERN_NOTICE "get_stram_region: out of memory\n" ); + return( -ENOMEM ); + } + DPRINTK( "unswap: reading swap page %lu to %08lx\n", i, page ); + read_swap_page( entry, (char *)page ); + + for_each_task(p) { + if (unswap_process( p->mm, entry, page, 0 )) { + page = 0; +#ifdef DO_PROC + stat_swap_force++; +#endif + break; + } + } + if (page) { + /* + * If we couldn't find an entry, there are several + * possible reasons: someone else freed it first, + * we freed the last reference to an overflowed entry, + * or the system has lost track of the use counts. + */ + if (map[i] && map[i] != SWP_RSVD-1) + printk( KERN_ERR "get_stram_region: swap entry %08lx " + "not used by any process\n", entry ); + /* quit while loop and overwrite bad map entry */ + if (!map[i]) { + DPRINTK( "unswap: map[i] became 0\n" ); + } + break; + } + } + + DPRINTK( "unswap: map[i=%lu]=%u nr_swap=%u\n", + i, map[i], nr_swap_pages ); + map[i] = SWP_RSVD; + if (stram_swap_info->lowest_bit == i) + stram_swap_info->lowest_bit++; + if (stram_swap_info->highest_bit == i) + stram_swap_info->highest_bit--; + --nr_swap_pages; + } + + if (page) + free_page(page); + return( 0 ); +} + +/* + * reserve a region in ST-RAM swap space for an allocation + */ +static void *get_stram_region( unsigned long n_pages ) +{ + unsigned char *map = stram_swap_info->swap_map; + unsigned long max = stram_swap_info->max; + unsigned long start, total_free, region_free; + int err; + void *ret = NULL; + + DPRINTK( "get_stram_region(n_pages=%lu)\n", n_pages ); + + /* disallow writing to the swap device now */ + stram_swap_info->flags = SWP_USED; + + /* find a region of n_pages pages in the swap space including as much free + * pages as possible (and excluding any already-reserved pages). */ + if (!(start = find_free_region( n_pages, &total_free, ®ion_free ))) + goto end; + DPRINTK( "get_stram_region: region starts at %lu, has %lu free pages\n", + start, region_free ); + + err = ((total_free-region_free >= n_pages-region_free) ? + unswap_by_move( map, max, start, n_pages ) : + unswap_by_read( map, max, start, n_pages )); + if (err) + goto end; + + ret = SWAP_ADDR(start); + end: + /* allow using swap device again */ + stram_swap_info->flags = SWP_WRITEOK; + DPRINTK( "get_stram_region: returning %p\n", ret ); + return( ret ); +} + + +/* + * free a reserved region in ST-RAM swap space + */ +static void free_stram_region( unsigned long offset, unsigned long n_pages ) +{ + unsigned char *map = stram_swap_info->swap_map; + + DPRINTK( "free_stram_region(offset=%lu,n_pages=%lu)\n", offset, n_pages ); + + if (offset < 1 || offset + n_pages > stram_swap_info->max) { + printk( KERN_ERR "free_stram_region: Trying to free non-ST-RAM\n" ); + return; + } + + /* un-reserve the freed pages */ + for( ; n_pages > 0; ++offset, --n_pages ) { + if (map[offset] != SWP_RSVD) + printk( KERN_ERR "free_stram_region: Swap page %lu was not " + "reserved\n", offset ); + map[offset] = 0; + } + + /* update swapping meta-data */ + if (offset < stram_swap_info->lowest_bit) + stram_swap_info->lowest_bit = offset; + if (offset+n_pages-1 > stram_swap_info->highest_bit) + stram_swap_info->highest_bit = offset+n_pages-1; + if (stram_swap_info->prio > swap_info[swap_list.next].prio) + swap_list.next = swap_list.head; + nr_swap_pages += n_pages; +} + + +/* ------------------------------------------------------------------------ */ +/* Utility Functions for Swapping */ +/* ------------------------------------------------------------------------ */ + + +/* is addr in some of the allocated regions? */ +static int in_some_region( unsigned long addr ) +{ + BLOCK *p; + + for( p = alloc_list; p; p = p->next ) { + if (p->start <= addr && addr < p->start + p->size) + return( 1 ); + } + return( 0 ); +} + + +static unsigned long find_free_region( unsigned long n_pages, + unsigned long *total_free, + unsigned long *region_free ) +{ + unsigned char *map = stram_swap_info->swap_map; + unsigned long max = stram_swap_info->max; + unsigned long head, tail, max_start; + long nfree, max_free; + + /* first scan the swap space for a suitable place for the allocation */ + head = 1; + max_start = 0; + max_free = -1; + *total_free = 0; + + start_over: + /* increment tail until final window size reached, and count free pages */ + nfree = 0; + for( tail = head; tail-head < n_pages && tail < max-n_pages; ++tail ) { + if (map[tail] == SWP_RSVD) { + head = tail+1; + goto start_over; + } + if (!map[tail]) { + ++nfree; + ++*total_free; } } + if (tail-head < n_pages) + goto out; + if (nfree > max_free) { + max_start = head; + max_free = nfree; + if (max_free >= n_pages) + /* don't need more free pages... :-) */ + goto out; + } - return( adr ); + /* now shift the window and look for the area where as much pages as + * possible are free */ + while( tail < max ) { + nfree -= (map[head++] == 0); + if (map[tail] == SWP_RSVD) { + head = tail+1; + goto start_over; + } + if (!map[tail]) { + ++nfree; + ++*total_free; + } + ++tail; + if (nfree > max_free) { + max_start = head; + max_free = nfree; + if (max_free >= n_pages) + /* don't need more free pages... :-) */ + goto out; + } + } + + out: + if (max_free < 0) { + printk( KERN_NOTICE "get_stram_region: ST-RAM too full or fragmented " + "-- can't allocate %lu pages\n", n_pages ); + return( 0 ); + } + + *region_free = max_free; + return( max_start ); } -void atari_stram_free( void *ptr ) +/* setup parameters from command line */ +void stram_swap_setup( char *str, int *ints ) { - /* Sorry, this is a dummy. It isn't needed anyway. */ + if (ints[0] >= 1) + max_swap_size = ((ints[1] < 0 ? 0 : ints[1]) * 1024) & PAGE_MASK; } + +/* ------------------------------------------------------------------------ */ +/* ST-RAM device */ +/* ------------------------------------------------------------------------ */ + +static int stram_blocksizes[14] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4096 }; +static int stram_sizes[14] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static int refcnt = 0; + +static void do_stram_request( void ) +{ + unsigned long start, len; + + while( CURRENT ) { + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic("stram: request list destroyed"); + if (CURRENT->bh) { + if (!buffer_locked(CURRENT->bh)) + panic("stram: block not locked"); + } + + start = swap_start + (CURRENT->sector << 9); + len = CURRENT->current_nr_sectors << 9; + if ((start + len) > swap_end) { + printk( KERN_ERR "stram: bad access beyond end of device: " + "block=%ld, count=%ld\n", + CURRENT->sector, + CURRENT->current_nr_sectors ); + end_request( 0 ); + continue; + } + + if (CURRENT->cmd == READ) { + memcpy( CURRENT->buffer, (char *)start, len ); +#ifdef DO_PROC + stat_swap_read += N_PAGES(len); #endif + } + else { + memcpy( (char *)start, CURRENT->buffer, len ); +#ifdef DO_PROC + stat_swap_write += N_PAGES(len); +#endif + } + end_request( 1 ); + } +} +static int stram_open( struct inode *inode, struct file *filp ) +{ + if (filp != MAGIC_FILE_P) { + printk( KERN_NOTICE "Only kernel can open ST-RAM device\n" ); + return( -EPERM ); + } + if (MINOR(inode->i_rdev) != STRAM_MINOR) + return( -ENXIO ); + if (refcnt) + return( -EBUSY ); + ++refcnt; + return( 0 ); +} + +static int stram_release( struct inode *inode, struct file *filp ) +{ + if (filp != MAGIC_FILE_P) { + printk( KERN_NOTICE "Only kernel can close ST-RAM device\n" ); + return( -EPERM ); + } + if (refcnt > 0) + --refcnt; + return( 0 ); +} + + +static struct file_operations stram_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + stram_open, /* open */ + stram_release, /* release */ + block_fsync /* fsync */ +}; + +int stram_device_init( void ) +{ + + if (!MACH_IS_ATARI) + /* no point in initializing this, I hope */ + return( -ENXIO ); + + if (!max_swap_size) + /* swapping not enabled */ + return( -ENXIO ); + + if (register_blkdev( STRAM_MAJOR, "stram", &stram_fops)) { + printk( KERN_ERR "stram: Unable to get major %d\n", STRAM_MAJOR ); + return( -ENXIO ); + } + + blk_dev[STRAM_MAJOR].request_fn = do_stram_request; + blksize_size[STRAM_MAJOR] = stram_blocksizes; + stram_sizes[STRAM_MINOR] = (swap_end - swap_start)/1024; + blk_size[STRAM_MAJOR] = stram_sizes; + do_z2_request(); /* to avoid warning */ + return( 0 ); +} + +/* to avoid warning */ +static void do_z2_request( void ) { } + +#endif /* CONFIG_STRAM_SWAP */ + + +/* ------------------------------------------------------------------------ */ +/* Misc Utility Functions */ +/* ------------------------------------------------------------------------ */ + + +/* return log2 of #pages for size */ +static int get_gfp_order( unsigned long size ) +{ + int order; + + size = N_PAGES( size + PAGE_SIZE -1 ); + order = -1; + do { + size >>= 1; + order++; + } while (size); + + return( order ); +} + + +/* reserve a range of pages in mem_map[] */ +static void reserve_region( unsigned long addr, unsigned long end ) +{ + mem_map_t *mapp = &mem_map[MAP_NR(addr)]; + + for( ; addr < end; addr += PAGE_SIZE, ++mapp ) + set_bit( PG_reserved, &mapp->flags ); +} + + + +/* ------------------------------------------------------------------------ */ +/* Region Management */ +/* ------------------------------------------------------------------------ */ + + +/* insert a region into the alloced list (sorted) */ +static BLOCK *add_region( void *addr, unsigned long size ) +{ + BLOCK **p, *n = NULL; + int i; + + for( i = 0; i < N_STATIC_BLOCKS; ++i ) { + if (static_blocks[i].flags & BLOCK_FREE) { + n = &static_blocks[i]; + n->flags = 0; + break; + } + } + if (!n && mem_init_done) { + /* if statics block pool exhausted and we can call kmalloc() already + * (after mem_init()), try that */ + n = kmalloc( sizeof(BLOCK), GFP_KERNEL ); + if (n) + n->flags = BLOCK_KMALLOCED; + } + if (!n) { + printk( KERN_ERR "Out of memory for ST-RAM descriptor blocks\n" ); + return( NULL ); + } + n->start = (unsigned long)addr; + n->size = size; + + for( p = &alloc_list; *p; p = &((*p)->next) ) + if ((*p)->start > (unsigned long)addr) break; + n->next = *p; + *p = n; + + return( n ); +} + + +/* find a region (by start addr) in the alloced list */ +static BLOCK *find_region( void *addr ) +{ + BLOCK *p; + + for( p = alloc_list; p; p = p->next ) { + if (p->start == (unsigned long)addr) + return( p ); + if (p->start > (unsigned long)addr) + break; + } + return( NULL ); +} + + +/* remove a block from the alloced list */ +static int remove_region( BLOCK *block ) +{ + BLOCK **p; + + for( p = &alloc_list; *p; p = &((*p)->next) ) + if (*p == block) break; + if (!*p) + return( 0 ); + + *p = block->next; + if (block->flags & BLOCK_KMALLOCED) + kfree( block ); + else + block->flags |= BLOCK_FREE; + return( 1 ); +} + + + +/* ------------------------------------------------------------------------ */ +/* /proc statistics file stuff */ +/* ------------------------------------------------------------------------ */ + +#ifdef DO_PROC + +#define PRINT_PROC(fmt,args...) len += sprintf( buf+len, fmt, ##args ) + +int get_stram_list( char *buf ) +{ + int len = 0; + BLOCK *p; +#ifdef CONFIG_STRAM_SWAP + int i; + unsigned char *map = stram_swap_info->swap_map; + unsigned long max = stram_swap_info->max; + unsigned free = 0, used = 0, rsvd = 0; +#endif + +#ifdef CONFIG_STRAM_SWAP + if (max_swap_size) { + for( i = 1; i < max; ++i ) { + if (!map[i]) + ++free; + else if (map[i] == SWP_RSVD) + ++rsvd; + else + ++used; + } + PRINT_PROC( + "Total ST-RAM: %8lu kB\n" + "Total ST-RAM swap: %8lu kB\n" + "Free swap: %8u kB\n" + "Used swap: %8u kB\n" + "Allocated swap: %8u kB\n" + "Swap Reads: %8u\n" + "Swap Writes: %8u\n" + "Swap Moves: %8u\n" + "Swap Forced Reads: %8u\n", + (stram_end - stram_start) >> 10, + (max-1) << (PAGE_SHIFT-10), + free << (PAGE_SHIFT-10), + used << (PAGE_SHIFT-10), + rsvd << (PAGE_SHIFT-10), + stat_swap_read, + stat_swap_write, + stat_swap_move, + stat_swap_force ); + } + else { +#endif + PRINT_PROC( "ST-RAM swapping disabled\n" ); + PRINT_PROC( + "Total ST-RAM: %8lu kB\n" + "Reserved ST-RAM: %8lu kB\n", + (stram_end - stram_start) >> 10, + (rsvd_stram_end - rsvd_stram_beg) >> 10 ); +#ifdef CONFIG_STRAM_SWAP + } +#endif + + PRINT_PROC( "Allocated regions:\n" ); + for( p = alloc_list; p; p = p->next ) { + if (len + 50 >= PAGE_SIZE) + break; + PRINT_PROC( "0x%08lx-0x%08lx: %s (", + VTOP(p->start), VTOP(p->start+p->size-1), p->owner ); + if (p->flags & BLOCK_STATIC) + PRINT_PROC( "static)\n" ); + else if (p->flags & BLOCK_GFP) + PRINT_PROC( "page-alloced)\n" ); + else if (p->flags & BLOCK_INSWAP) + PRINT_PROC( "in swap)\n" ); + else + PRINT_PROC( "??)\n" ); + } + + return( len ); +} + +#endif + + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 4 + * End: + */ diff -ur --new-file old/linux/arch/m68k/atari/time.c new/linux/arch/m68k/atari/time.c --- old/linux/arch/m68k/atari/time.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/atari/time.c Sat Feb 21 03:28:21 1998 @@ -0,0 +1,415 @@ +/* + * linux/arch/m68k/atari/time.c + * + * Atari time and real time clock stuff + * + * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include + + +__initfunc(void +atari_sched_init(void (*timer_routine)(int, void *, struct pt_regs *))) +{ + /* set Timer C data Register */ + mfp.tim_dt_c = INT_TICKS; + /* start timer C, div = 1:100 */ + mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60; + /* install interrupt service routine for MFP Timer C */ + request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW, + "timer", timer_routine); +} + +/* ++andreas: gettimeoffset fixed to check for pending interrupt */ + +#define TICK_SIZE 10000 + +/* This is always executed with interrupts disabled. */ +unsigned long atari_gettimeoffset (void) +{ + unsigned long ticks, offset = 0; + + /* read MFP timer C current value */ + ticks = mfp.tim_dt_c; + /* The probability of underflow is less than 2% */ + if (ticks > INT_TICKS - INT_TICKS / 50) + /* Check for pending timer interrupt */ + if (mfp.int_pn_b & (1 << 5)) + offset = TICK_SIZE; + + ticks = INT_TICKS - ticks; + ticks = ticks * 10000L / INT_TICKS; + + return ticks + offset; +} + + +static void mste_read(struct MSTE_RTC *val) +{ +#define COPY(v) val->v=(mste_rtc.v & 0xf) + do { + COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; + COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; + COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; + COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; + COPY(year_tens) ; + /* prevent from reading the clock while it changed */ + } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); +#undef COPY +} + +static void mste_write(struct MSTE_RTC *val) +{ +#define COPY(v) mste_rtc.v=val->v + do { + COPY(sec_ones) ; COPY(sec_tens) ; COPY(min_ones) ; + COPY(min_tens) ; COPY(hr_ones) ; COPY(hr_tens) ; + COPY(weekday) ; COPY(day_ones) ; COPY(day_tens) ; + COPY(mon_ones) ; COPY(mon_tens) ; COPY(year_ones) ; + COPY(year_tens) ; + /* prevent from writing the clock while it changed */ + } while (val->sec_ones != (mste_rtc.sec_ones & 0xf)); +#undef COPY +} + +#define RTC_READ(reg) \ + ({ unsigned char __val; \ + outb(reg,&tt_rtc.regsel); \ + __val = tt_rtc.data; \ + __val; \ + }) + +#define RTC_WRITE(reg,val) \ + do { \ + outb(reg,&tt_rtc.regsel); \ + tt_rtc.data = (val); \ + } while(0) + + +void atari_mste_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + int hr24=0, hour; + struct MSTE_RTC val; + + mste_rtc.mode=(mste_rtc.mode | 1); + hr24=mste_rtc.mon_tens & 1; + mste_rtc.mode=(mste_rtc.mode & ~1); + + mste_read(&val); + *secp = val.sec_ones + val.sec_tens * 10; + *minp = val.min_ones + val.min_tens * 10; + hour = val.hr_ones + val.hr_tens * 10; + if (!hr24) { + if (hour == 12 || hour == 12 + 20) + hour -= 12; + if (hour >= 20) + hour += 12 - 20; + } + *hourp = hour; + *dayp = val.day_ones + val.day_tens * 10; + *monp = val.mon_ones + val.mon_tens * 10; + *yearp = val.year_ones + val.year_tens * 10 + 80; +} + + +void atari_tt_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + unsigned char ctrl; + int hour, pm; + + while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ; + while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ; + + *secp = RTC_READ(RTC_SECONDS); + *minp = RTC_READ(RTC_MINUTES); + hour = RTC_READ(RTC_HOURS); + *dayp = RTC_READ(RTC_DAY_OF_MONTH); + *monp = RTC_READ(RTC_MONTH); + *yearp = RTC_READ(RTC_YEAR); + pm = hour & 0x80; + hour &= ~0x80; + + ctrl = RTC_READ(RTC_CONTROL); + + if (!(ctrl & RTC_DM_BINARY)) { + BCD_TO_BIN(*secp); + BCD_TO_BIN(*minp); + BCD_TO_BIN(hour); + BCD_TO_BIN(*dayp); + BCD_TO_BIN(*monp); + BCD_TO_BIN(*yearp); + } + if (!(ctrl & RTC_24H)) { + if (!pm && hour == 12) + hour = 0; + else if (pm && hour != 12) + hour += 12; + } + *hourp = hour; + + /* Adjust values (let the setup valid) */ + *yearp += atari_rtc_year_offset; +} + +#define HWCLK_POLL_INTERVAL 5 + +int atari_mste_hwclk( int op, struct hwclk_time *t ) +{ + int hour, year; + int hr24=0; + struct MSTE_RTC val; + + mste_rtc.mode=(mste_rtc.mode | 1); + hr24=mste_rtc.mon_tens & 1; + mste_rtc.mode=(mste_rtc.mode & ~1); + + if (op) { + /* write: prepare values */ + + val.sec_ones = t->sec % 10; + val.sec_tens = t->sec / 10; + val.min_ones = t->min % 10; + val.min_tens = t->min / 10; + hour = t->hour; + if (!hr24) { + if (hour > 11) + hour += 20 - 12; + if (hour == 0 || hour == 20) + hour += 12; + } + val.hr_ones = hour % 10; + val.hr_tens = hour / 10; + val.day_ones = t->day % 10; + val.day_tens = t->day / 10; + val.mon_ones = (t->mon+1) % 10; + val.mon_tens = (t->mon+1) / 10; + year = t->year - 80; + val.year_ones = year % 10; + val.year_tens = year / 10; + val.weekday = t->wday; + mste_write(&val); + mste_rtc.mode=(mste_rtc.mode | 1); + val.year_ones = (year % 4); /* leap year register */ + mste_rtc.mode=(mste_rtc.mode & ~1); + } + else { + mste_read(&val); + t->sec = val.sec_ones + val.sec_tens * 10; + t->min = val.min_ones + val.min_tens * 10; + hour = val.hr_ones + val.hr_tens * 10; + if (!hr24) { + if (hour == 12 || hour == 12 + 20) + hour -= 12; + if (hour >= 20) + hour += 12 - 20; + } + t->hour = hour; + t->day = val.day_ones + val.day_tens * 10; + t->mon = val.mon_ones + val.mon_tens * 10 - 1; + t->year = val.year_ones + val.year_tens * 10 + 80; + t->wday = val.weekday; + } + return 0; +} + +int atari_tt_hwclk( int op, struct hwclk_time *t ) +{ + int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0; + unsigned long flags; + unsigned char ctrl; + int pm = 0; + + ctrl = RTC_READ(RTC_CONTROL); /* control registers are + * independent from the UIP */ + + if (op) { + /* write: prepare values */ + + sec = t->sec; + min = t->min; + hour = t->hour; + day = t->day; + mon = t->mon + 1; + year = t->year - atari_rtc_year_offset; + wday = t->wday + (t->wday >= 0); + + if (!(ctrl & RTC_24H)) { + if (hour > 11) { + pm = 0x80; + if (hour != 12) + hour -= 12; + } + else if (hour == 0) + hour = 12; + } + + if (!(ctrl & RTC_DM_BINARY)) { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hour); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(year); + if (wday >= 0) BIN_TO_BCD(wday); + } + } + + /* Reading/writing the clock registers is a bit critical due to + * the regular update cycle of the RTC. While an update is in + * progress, registers 0..9 shouldn't be touched. + * The problem is solved like that: If an update is currently in + * progress (the UIP bit is set), the process sleeps for a while + * (50ms). This really should be enough, since the update cycle + * normally needs 2 ms. + * If the UIP bit reads as 0, we have at least 244 usecs until the + * update starts. This should be enough... But to be sure, + * additionally the RTC_SET bit is set to prevent an update cycle. + */ + + while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HWCLK_POLL_INTERVAL; + schedule(); + } + + save_flags(flags); + cli(); + RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET ); + if (!op) { + sec = RTC_READ( RTC_SECONDS ); + min = RTC_READ( RTC_MINUTES ); + hour = RTC_READ( RTC_HOURS ); + day = RTC_READ( RTC_DAY_OF_MONTH ); + mon = RTC_READ( RTC_MONTH ); + year = RTC_READ( RTC_YEAR ); + wday = RTC_READ( RTC_DAY_OF_WEEK ); + } + else { + RTC_WRITE( RTC_SECONDS, sec ); + RTC_WRITE( RTC_MINUTES, min ); + RTC_WRITE( RTC_HOURS, hour + pm); + RTC_WRITE( RTC_DAY_OF_MONTH, day ); + RTC_WRITE( RTC_MONTH, mon ); + RTC_WRITE( RTC_YEAR, year ); + if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday ); + } + RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET ); + restore_flags(flags); + + if (!op) { + /* read: adjust values */ + + if (hour & 0x80) { + hour &= ~0x80; + pm = 1; + } + + if (!(ctrl & RTC_DM_BINARY)) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + BCD_TO_BIN(wday); + } + + if (!(ctrl & RTC_24H)) { + if (!pm && hour == 12) + hour = 0; + else if (pm && hour != 12) + hour += 12; + } + + t->sec = sec; + t->min = min; + t->hour = hour; + t->day = day; + t->mon = mon - 1; + t->year = year + atari_rtc_year_offset; + t->wday = wday - 1; + } + + return( 0 ); +} + + +int atari_mste_set_clock_mmss (unsigned long nowtime) +{ + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + struct MSTE_RTC val; + unsigned char rtc_minutes; + + mste_read(&val); + rtc_minutes= val.min_ones + val.min_tens * 10; + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + val.sec_ones = real_seconds % 10; + val.sec_tens = real_seconds / 10; + val.min_ones = real_minutes % 10; + val.min_tens = real_minutes / 10; + mste_write(&val); + } + else + return -1; + return 0; +} + +int atari_tt_set_clock_mmss (unsigned long nowtime) +{ + int retval = 0; + short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; + unsigned char save_control, save_freq_select, rtc_minutes; + + save_control = RTC_READ (RTC_CONTROL); /* tell the clock it's being set */ + RTC_WRITE (RTC_CONTROL, save_control | RTC_SET); + + save_freq_select = RTC_READ (RTC_FREQ_SELECT); /* stop and reset prescaler */ + RTC_WRITE (RTC_FREQ_SELECT, save_freq_select | RTC_DIV_RESET2); + + rtc_minutes = RTC_READ (RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY)) + BCD_TO_BIN (rtc_minutes); + + /* Since we're only adjusting minutes and seconds, don't interfere + with hour overflow. This avoids messing with unknown time zones + but requires your RTC not to be off by more than 30 minutes. */ + if ((rtc_minutes < real_minutes + ? real_minutes - rtc_minutes + : rtc_minutes - real_minutes) < 30) + { + if (!(save_control & RTC_DM_BINARY)) + { + BIN_TO_BCD (real_seconds); + BIN_TO_BCD (real_minutes); + } + RTC_WRITE (RTC_SECONDS, real_seconds); + RTC_WRITE (RTC_MINUTES, real_minutes); + } + else + retval = -1; + + RTC_WRITE (RTC_FREQ_SELECT, save_freq_select); + RTC_WRITE (RTC_CONTROL, save_control); + return retval; +} + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -ur --new-file old/linux/arch/m68k/config.in new/linux/arch/m68k/config.in --- old/linux/arch/m68k/config.in Tue Dec 2 20:41:44 1997 +++ new/linux/arch/m68k/config.in Tue Mar 10 23:43:13 1998 @@ -14,7 +14,7 @@ bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD + bool 'Kernel module loader' CONFIG_KMOD fi endmenu @@ -23,7 +23,19 @@ bool 'Amiga support' CONFIG_AMIGA bool 'Atari support' CONFIG_ATARI +if [ "$CONFIG_ATARI" = "y" ]; then + bool ' Hades support' CONFIG_HADES + if [ "$CONFIG_HADES" = "y" ]; then + define_bool CONFIG_PCI y + fi +fi bool 'Macintosh support' CONFIG_MAC +bool 'Apollo support' CONFIG_APOLLO +bool 'VME (Motorola and BVM) support' CONFIG_VME +if [ "$CONFIG_VME" = "y" ]; then + bool 'MVME162, 166 and 167 support' CONFIG_MVME16x +# bool 'BVME4000 and BVME6000 support' CONFIG_BVME6000 +fi comment 'Processor type' bool '68020 support' CONFIG_M68020 @@ -56,19 +68,19 @@ if [ "$CONFIG_AMIGA" = "y" ]; then bool 'Amiga AutoConfig Identification' CONFIG_ZORRO - bool 'Amiga OCS chipset support' CONFIG_AMIFB_OCS - bool 'Amiga ECS chipset support' CONFIG_AMIFB_ECS - bool 'Amiga AGA chipset support' CONFIG_AMIFB_AGA - bool 'Amiga Cybervision support' CONFIG_FB_CYBER - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Amiga RetinaZ3 support' CONFIG_FB_RETINAZ3 - fi # bool 'Amiga GSP (TMS340x0) support' CONFIG_AMIGA_GSP # if [ "$CONFIG_AMIGA_GSP" = "y" ]; then # bool 'DMI Resolver support' CONFIG_GSP_RESOLVER # bool 'A2410 support' CONFIG_GSP_A2410 # fi fi +if [ "$CONFIG_ATARI" = "y" ]; then + bool 'Support for ST-RAM as swap space' CONFIG_STRAM_SWAP + bool 'ST-RAM statistics in /proc' CONFIG_STRAM_PROC +fi +if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then + bool 'Use power LED as a heartbeat' CONFIG_HEARTBEAT +fi endmenu # @@ -77,7 +89,17 @@ mainmenu_option next_comment comment 'Floppy, IDE, and other block devices' -tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD +if [ "$CONFIG_AMIGA" = "y" ]; then + tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY +fi +if [ "$CONFIG_ATARI" = "y" ]; then + tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY +fi +if [ "$CONFIG_MAC" = "y" ]; then + tristate 'Macintosh IWM floppy support' CONFIG_MAC_FLOPPY +fi +#Normal floppy disk support' CONFIG_BLK_DEV_FD + tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE @@ -85,6 +107,16 @@ dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE + if [ "$CONFIG_AMIGA" = "y" ]; then + bool ' Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' Buddha/Catweasel IDE interface support' CONFIG_BLK_DEV_BUDDHA + bool ' Amiga IDE Doubler support' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE + fi + fi + if [ "$CONFIG_ATARI" = "y" ]; then + bool ' Falcon IDE interface support' CONFIG_BLK_DEV_FALCON_IDE + fi fi if [ "$CONFIG_AMIGA" = "y" ]; then tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM @@ -129,7 +161,7 @@ dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR fi dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI @@ -138,6 +170,7 @@ bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS +bool 'SCSI logging facility' CONFIG_SCSI_LOGGING mainmenu_option next_comment comment 'SCSI low-level drivers' @@ -155,14 +188,26 @@ bool 'A4000T SCSI support' CONFIG_A4000T_SCSI bool 'A4091 SCSI support' CONFIG_A4091_SCSI bool 'WarpEngine SCSI support' CONFIG_WARPENGINE_SCSI - bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI + bool 'Cyberstorm Mk III SCSI support' CONFIG_CYBERSTORMIII_SCSI +# bool 'GVP Turbo 040/060 SCSI support' CONFIG_GVP_TURBO_SCSI fi fi if [ "$CONFIG_ATARI" = "y" ]; then dep_tristate 'Atari native SCSI support' CONFIG_ATARI_SCSI $CONFIG_SCSI bool 'Long delays for Toshiba CD-ROMs' CONFIG_ATARI_SCSI_TOSHIBA_DELAY + if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_HADES" = "y" ]; then + bool 'Hades SCSI DMA emulator (EXPERIMENTAL)' CONFIG_TT_DMA_EMUL + fi +fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI fi #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI + +if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then + bool 'NCR53C710 SCSI driver for MVME16x' CONFIG_MVME16x_SCSI +fi + endmenu fi @@ -195,12 +240,21 @@ tristate 'A2065 support' CONFIG_A2065 tristate 'Hydra support' CONFIG_HYDRA fi +if [ "$CONFIG_APOLLO" = "y" ] ; then + tristate 'Apollo 3c505 support' CONFIG_APOLLO_ELPLUS +fi if [ "$CONFIG_ATARI" = "y" ]; then - bool 'Atari Lance support' CONFIG_ATARILANCE -if [ "$CONFIG_ATARI_ACSI" = "y" ]; then - bool 'BioNet-100 support' CONFIG_ATARI_BIONET - bool 'PAMsNet support' CONFIG_ATARI_PAMSNET + tristate 'Atari Lance support' CONFIG_ATARILANCE + if [ "$CONFIG_ATARI_ACSI" != "n" ]; then + tristate 'BioNet-100 support' CONFIG_ATARI_BIONET + tristate 'PAMsNet support' CONFIG_ATARI_PAMSNET + fi +fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'Mac NS 8390 based ethernet cards' CONFIG_DAYNAPORT fi +if [ "$CONFIG_VME" = "y" -a "$CONFIG_MVME16x" = "y" ]; then + bool 'MVME16x Ethernet support' CONFIG_APRICOT fi fi endmenu @@ -220,14 +274,23 @@ source fs/Config.in +if [ "$CONFIG_VME" = "n" ]; then + define_bool CONFIG_FB y + source drivers/video/Config.in +fi + source fs/nls/Config.in mainmenu_option next_comment comment 'Character devices' - -define_bool CONFIG_VT y -define_bool CONFIG_VT_CONSOLE y -define_bool CONFIG_FB_CONSOLE y + +if [ "$CONFIG_VME" = "n" ]; then + define_bool CONFIG_VT y + if [ "$CONFIG_VT" = "y" ]; then + bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE + fi + define_bool CONFIG_FB_CONSOLE y +fi if [ "$CONFIG_ATARI" = "y" ]; then define_bool CONFIG_NVRAM y @@ -241,6 +304,9 @@ if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari mouse support' CONFIG_ATARIMOUSE fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'Mac ADB mouse support' CONFIG_MACMOUSE +fi if [ "$CONFIG_ATARI" = "y" ]; then tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER tristate 'Atari SCC serial support' CONFIG_ATARI_SCC @@ -260,11 +326,25 @@ tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET fi -if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \ - "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \ - "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then - bool 'Serial console support' CONFIG_SERIAL_CONSOLE +if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then + if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \ + "$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \ + "$CONFIG_GVPIOEXT" = "y" -o "$CONFIG_MULTIFACE_III_TTY" = "y" ]; then + bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE + fi +fi +if [ "$CONFIG_MAC" = "y" ]; then + bool 'Mac SCC serial support' CONFIG_MAC_SCC fi +if [ "$CONFIG_VME" = "y" ]; then + define_bool CONFIG_SERIAL_CONSOLE y + bool 'CD2401 support for MVME166/7 serial ports' CONFIG_SERIAL167 + bool 'SCC support for MVME162 serial ports' CONFIG_MVME162_SCC +fi +if [ "$CONFIG_APOLLO" = "y" ]; then + bool 'Support for DN serial port (dummy)' CONFIG_SERIAL + bool 'Support for serial port console' CONFIG_SERIAL_CONSOLE +fi bool 'Support for user serial device modules' CONFIG_USERIAL bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then @@ -274,6 +354,9 @@ bool 'Support for user misc device modules' CONFIG_UMISC if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_ATARI" = "y" ]; then define_bool CONFIG_ABSTRACT_CONSOLE y +fi +if [ "$CONFIG_ATARI" = "y" ]; then + bool 'Enhanced Real Time Clock Support' CONFIG_RTC fi endmenu diff -ur --new-file old/linux/arch/m68k/defconfig new/linux/arch/m68k/defconfig --- old/linux/arch/m68k/defconfig Thu Jul 31 22:09:16 1997 +++ new/linux/arch/m68k/defconfig Tue Mar 10 23:43:13 1998 @@ -12,10 +12,10 @@ # # CONFIG_MODULES is not set # CONFIG_MODVERSIONS is not set -# CONFIG_KERNELD is not set +# CONFIG_KMOD is not set # -# Platform dependant setup +# Platform-dependent setup # CONFIG_AMIGA=y # CONFIG_ATARI is not set @@ -42,11 +42,6 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y CONFIG_ZORRO=y -CONFIG_AMIFB_OCS=y -CONFIG_AMIFB_ECS=y -CONFIG_AMIFB_AGA=y -# CONFIG_FB_CYBER is not set -# CONFIG_FB_RETINAZ3 is not set # CONFIG_AMIGA_GSP is not set # CONFIG_GSP_RESOLVER is not set # CONFIG_GSP_A2410 is not set @@ -54,7 +49,8 @@ # # Block device driver configuration # -CONFIG_BLK_DEV_FD=y +CONFIG_AMIGA_FLOPPY=y +CONFIG_ATARI_FLOPPY=y # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_IDE is not set # CONFIG_BLK_DEV_IDEDISK is not set @@ -62,6 +58,7 @@ # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_IDEDOUBLER is not set # CONFIG_AMIGA_Z2RAM is not set # CONFIG_ATARI_ACSI is not set # CONFIG_ACSI_MULTI_LUN is not set @@ -132,6 +129,9 @@ # CONFIG_BLZ2060_SCSI is not set # CONFIG_BLZ1230_SCSI is not set # CONFIG_FASTLANE_SCSI is not set +# CONFIG_A4000T_SCSI is not set +# CONFIG_A4091_SCSI is not set +# CONFIG_WARPENGINE_SCSI is not set CONFIG_ATARI_SCSI=y # @@ -169,6 +169,21 @@ # CONFIG_AFFS_FS is not set # CONFIG_ROMFS_FS is not set # CONFIG_UFS_FS is not set + +# +# Frame buffer devices +# +CONFIG_FB_AMIGA=y +CONFIG_FB_AMIGA_OCS=y +CONFIG_FB_AMIGA_ECS=y +CONFIG_FB_AMIGA_AGA=y +# CONFIG_FB_CYBER is not set +# CONFIG_FB_RETINAZ3 is not set +# CONFIG_FB_ATARI is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set + +CONFIG_NLS_CODEPAGE_437=y # # Character devices diff -ur --new-file old/linux/arch/m68k/ifpsp060/iskeleton.S new/linux/arch/m68k/ifpsp060/iskeleton.S --- old/linux/arch/m68k/ifpsp060/iskeleton.S Thu Jul 31 22:09:16 1997 +++ new/linux/arch/m68k/ifpsp060/iskeleton.S Fri Feb 13 01:30:12 1998 @@ -183,7 +183,7 @@ | | _060_lock_page(): | -| Entry point for the operating system's routine to "lock" a page +| Entry point for the operating system`s routine to "lock" a page | from being paged out. This routine is needed by the cas/cas2 | algorithms so that no page faults occur within the "core" code | region. Note: the routine must lock two pages if the operand @@ -208,7 +208,7 @@ | | _060_unlock_page(): | -| Entry point for the operating system's routine to "unlock" a +| Entry point for the operating system`s routine to "unlock" a | page that has been "locked" previously with _real_lock_page. | Note: the routine must unlock two pages if the operand spans | two pages. diff -ur --new-file old/linux/arch/m68k/ifpsp060/os.S new/linux/arch/m68k/ifpsp060/os.S --- old/linux/arch/m68k/ifpsp060/os.S Thu Apr 24 04:01:15 1997 +++ new/linux/arch/m68k/ifpsp060/os.S Fri Feb 13 01:30:12 1998 @@ -345,7 +345,6 @@ copyinae: movs.b (%a0)+,%d1 | fetch user byte move.b %d1,(%a1)+ | write supervisor byte - subq.l #0x1,%d0 | are we through yet? dbra %d0,morein | are we through yet? moveq #0,%d0 | return success rts diff -ur --new-file old/linux/arch/m68k/kernel/Makefile new/linux/arch/m68k/kernel/Makefile --- old/linux/arch/m68k/kernel/Makefile Sat Aug 16 18:51:07 1997 +++ new/linux/arch/m68k/kernel/Makefile Fri Feb 13 01:30:12 1998 @@ -10,19 +10,26 @@ .S.o: $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o -all: kernel.o head.o +all: head.o kernel.o O_TARGET := kernel.o O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \ setup.o sys_m68k.o time.o -ifdef CONFIG_VT -O_OBJS += console.o -endif OX_OBJS := m68k_ksyms.o ifdef CONFIG_KGDB O_OBJS += kgdb.o endif -head.o: head.S +ifdef CONFIG_PCI +O_OBJS += bios32.o +endif + +head.o: head.S m68k_defs.h + +m68k_defs.h: m68k_defs.c m68k_defs.head $(TOPDIR)/include/linux/sched.h + $(CC) ${CFLAGS} -S m68k_defs.c + cp m68k_defs.head m68k_defs.h + sed -n < m68k_defs.s >> m68k_defs.h '/^#define/s/ #/ /p' + rm m68k_defs.s include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/m68k/kernel/bios32.c new/linux/arch/m68k/kernel/bios32.c --- old/linux/arch/m68k/kernel/bios32.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/kernel/bios32.c Fri Feb 13 01:30:12 1998 @@ -0,0 +1,580 @@ +/* + * bios32.c - PCI BIOS functions for Alpha systems not using BIOS + * emulation code. + * + * Written by Wout Klaren. + * + * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger. + */ + +#include +#include +#include + +#if 0 +# define DBG_DEVS(args) printk args +#else +# define DBG_DEVS(args) +#endif + +#ifdef CONFIG_PCI + +/* + * PCI support for Linux/m68k. Currently only the Hades is supported. + * + * Notes: + * + * 1. The PCI memory area starts at address 0x80000000 and the + * I/O area starts at 0xB0000000. Therefore these offsets + * are added to the base addresses when they are read and + * substracted when they are written. + * + * 2. The support for PCI bridges in the DEC Alpha version has + * been removed in this version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define KB 1024 +#define MB (1024*KB) +#define GB (1024*MB) + +#define MAJOR_REV 0 +#define MINOR_REV 0 + +/* + * Base addresses of the PCI memory and I/O areas on the Hades. + */ + +static unsigned long pci_mem_base = 0; +static unsigned long pci_io_base = 0; + +/* + * Align VAL to ALIGN, which must be a power of two. + */ + +#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) + +/* + * Calculate the address of the PCI configuration area of the given + * device. + * + * BUG: boards with multiple functions are probably not correctly + * supported. + */ + +static int mk_conf_addr(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned long *pci_addr) +{ + static const unsigned long pci_conf_base[] = { 0xA0080000, 0xA0040000, + 0xA0020000, 0xA0010000 }; + int device = device_fn >> 3; + + DBG_DEVS(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p)\n", + bus, device_fn, where, pci_addr)); + + if (device > 3) { + DBG_DEVS(("mk_conf_addr: device (%d) > 3, returning -1\n", device)); + return -1; + } + + *pci_addr = pci_conf_base[device] | (where); + DBG_DEVS(("mk_conf_addr: returning pci_addr 0x%lx\n", *pci_addr)); + return 0; +} + +int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char *value) +{ + unsigned long pci_addr; + + *value = 0xff; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *((unsigned char *)pci_addr); + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_word(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short *value) +{ + unsigned long pci_addr; + + *value = 0xffff; + + if (where & 0x1) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = le16_to_cpu(*((unsigned short *)pci_addr)); + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_dword(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int *value) +{ + unsigned long pci_addr; + + *value = 0xffffffff; + + if (where & 0x3) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = le32_to_cpu(*((unsigned int *)pci_addr)); + + if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) + { + if ((*value & PCI_BASE_ADDRESS_SPACE) == + PCI_BASE_ADDRESS_SPACE_IO) + *value += pci_io_base; + else + { + if (*value == 0) + { + /* + * Base address is 0. Test if this base + * address register is used. + */ + + *((unsigned long *)pci_addr) = 0xffffffff; + if (*((unsigned long *)pci_addr) != 0) + *value += pci_mem_base; + } + else + *value += pci_mem_base; + } + } + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_byte(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char value) +{ + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + *((unsigned char *)pci_addr) = value; + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_word(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short value) +{ + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + *((unsigned short *)pci_addr) = cpu_to_le16(value); + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_dword(unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int value) +{ + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) + { + if ((value & PCI_BASE_ADDRESS_SPACE) == + PCI_BASE_ADDRESS_SPACE_IO) + value -= pci_io_base; + else + value -= pci_mem_base; + } + + *((unsigned int *)pci_addr) = cpu_to_le32(value); + + return PCIBIOS_SUCCESSFUL; +} + +/* + * Macro to enable programming of the PCI devices. On the Hades this + * define should be true, because the Hades has no PCI BIOS. + */ + +#define PCI_MODIFY 1 + +#if PCI_MODIFY + +/* + * Leave some room for a VGA card. We assume that the VGA card is + * always in the first 32M of PCI memory. For the time being we do + * not program the VGA card, because to make this work we also + * need to change the frame buffer device. + */ + +#define FIRST_IO_ADDR 0x10000 +#define FIRST_MEM_ADDR 0x02000000 + +static unsigned int io_base = FIRST_IO_ADDR; /* Skip first 64K. */ +static unsigned int mem_base = FIRST_MEM_ADDR; /* Skip first 32M. */ + +/* + * Disable PCI device DEV so that it does not respond to I/O or memory + * accesses. + */ + +__initfunc(static void disable_dev(struct pci_dev *dev)) +{ + struct pci_bus *bus; + unsigned short cmd; + + if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) + return; + + bus = dev->bus; + pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); + + cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); + pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, cmd); +} + +/* + * Layout memory and I/O for a device: + */ + +#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2) + +__initfunc(static void layout_dev(struct pci_dev *dev)) +{ + struct pci_bus *bus; + unsigned short cmd; + unsigned int base, mask, size, reg; + unsigned int alignto; + + /* + * Skip video cards for the time being. + */ + + if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) + return; + + bus = dev->bus; + pcibios_read_config_word(bus->number, dev->devfn, PCI_COMMAND, &cmd); + + for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) + { + /* + * Figure out how much space and of what type this + * device wants. + */ + + pcibios_write_config_dword(bus->number, dev->devfn, reg, + 0xffffffff); + pcibios_read_config_dword(bus->number, dev->devfn, reg, &base); + + if (!base) + { + /* this base-address register is unused */ + continue; + } + + /* + * We've read the base address register back after + * writing all ones and so now we must decode it. + */ + + if (base & PCI_BASE_ADDRESS_SPACE_IO) + { + /* + * I/O space base address register. + */ + + cmd |= PCI_COMMAND_IO; + + base &= PCI_BASE_ADDRESS_IO_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + /* align to multiple of size of minimum base */ + alignto = MAX(0x400, size) ; + base = ALIGN(io_base, alignto); + io_base = base + size; + pcibios_write_config_dword(bus->number, dev->devfn, + reg, base | 0x1); + DBG_DEVS(("layout_dev: IO address: %lX\n", base)); + } + else + { + unsigned int type; + + /* + * Memory space base address register. + */ + + cmd |= PCI_COMMAND_MEMORY; + type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK; + base &= PCI_BASE_ADDRESS_MEM_MASK; + mask = (~base << 1) | 0x1; + size = (mask & base) & 0xffffffff; + switch (type) + { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + break; + + case PCI_BASE_ADDRESS_MEM_TYPE_64: + printk("bios32 WARNING: " + "ignoring 64-bit device in " + "slot %d, function %d: \n", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + reg += 4; /* skip extra 4 bytes */ + continue; + + case PCI_BASE_ADDRESS_MEM_TYPE_1M: + printk("bios32 WARNING: slot %d, function %d " + "requests memory below 1MB---don't " + "know how to do that.\n", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + continue; + } + + /* + * Align to multiple of size of minimum base + */ + + alignto = MAX(0x1000, size) ; + base = ALIGN(mem_base, alignto); + mem_base = base + size; + pcibios_write_config_dword(bus->number, dev->devfn, + reg, base); + } + } + + /* + * Enable device: + */ + + if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED || + dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || + dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) + { + /* + * All of these (may) have I/O scattered all around + * and may not use i/o-base address registers at all. + * So we just have to always enable I/O to these + * devices. + */ + cmd |= PCI_COMMAND_IO; + } + + pcibios_write_config_word(bus->number, dev->devfn, PCI_COMMAND, + cmd | PCI_COMMAND_MASTER); + DBG_DEVS(("layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n", + bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class)); +} + +__initfunc(static void layout_bus(struct pci_bus *bus)) +{ + struct pci_dev *dev; + + DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); + + if (!bus->devices && !bus->children) + return; + + /* + * Align the current bases on appropriate boundaries (4K for + * IO and 1MB for memory). + */ + + io_base = ALIGN(io_base, 4*KB); + mem_base = ALIGN(mem_base, 1*MB); + + /* + * PCI devices might have been setup by a PCI BIOS emulation + * running under TOS. In these cases there is a + * window during which two devices may have an overlapping + * address range. To avoid this causing trouble, we first + * turn off the I/O and memory address decoders for all PCI + * devices. They'll be re-enabled only once all address + * decoders are programmed consistently. + */ + + for (dev = bus->devices; dev; dev = dev->sibling) + { + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) + disable_dev(dev); + } + + /* + * Allocate space to each device: + */ + + DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number)); + + for (dev = bus->devices; dev; dev = dev->sibling) + { + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) + layout_dev(dev); + } +} + +#endif /* !PCI_MODIFY */ + +/* + * Given the vendor and device ids, find the n'th instance of that device + * in the system. + */ + +int pcibios_find_device(unsigned short vendor, unsigned short device_id, + unsigned short index, unsigned char *bus, + unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) + { + if (dev->vendor == vendor && dev->device == device_id) + { + if (curr == index) + { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +/* + * Given the class, find the n'th instance of that device + * in the system. + */ + +int pcibios_find_class(unsigned int class_code, unsigned short index, + unsigned char *bus, unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) + { + if (dev->class == class_code) + { + if (curr == index) + { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +int pcibios_present(void) +{ + if (MACH_IS_HADES) + return 1; + else + return 0; +} + +__initfunc(unsigned long pcibios_init(unsigned long mem_start, + unsigned long mem_end)) +{ + printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); + +#if !PCI_MODIFY + printk("...NOT modifying existing PCI configuration\n"); +#endif + + return mem_start; +} + +/* + * static inline void hades_fixup(void) + * + * Assign IRQ numbers as used by Linux to the interrupt pins + * of the PCI cards. + */ + +__initfunc(static inline void hades_fixup(void)) +{ + char irq_tab[4] = { + IRQ_TT_MFP_IO0, /* Slot 0. */ + IRQ_TT_MFP_IO1, /* Slot 1. */ + IRQ_TT_MFP_SCC, /* Slot 2. */ + IRQ_TT_MFP_SCSIDMA /* Slot 3. */ + }; + struct pci_dev *dev; + unsigned char slot; + + /* + * Go through all devices, fixing up irqs as we see fit: + */ + + for (dev = pci_devices; dev; dev = dev->next) + { + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) + { + slot = PCI_SLOT(dev->devfn); /* Determine slot number. */ + dev->irq = irq_tab[slot]; +#if PCI_MODIFY + pcibios_write_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_LINE, dev->irq); +#endif + } + } +} + +__initfunc(unsigned long pcibios_fixup(unsigned long mem_start, + unsigned long mem_end)) +{ +#if PCI_MODIFY + /* + * Scan the tree, allocating PCI memory and I/O space. + */ + + layout_bus(&pci_root); +#endif + + pci_mem_base = 0x80000000; + pci_io_base = 0xB0000000; + + /* + * Now is the time to do all those dirty little deeds... + */ + + hades_fixup(); + + return mem_start; +} +#endif /* CONFIG_PCI */ diff -ur --new-file old/linux/arch/m68k/kernel/console.c new/linux/arch/m68k/kernel/console.c --- old/linux/arch/m68k/kernel/console.c Thu Jul 31 22:09:16 1997 +++ new/linux/arch/m68k/kernel/console.c Thu Jan 1 01:00:00 1970 @@ -1,2748 +0,0 @@ -/* - * linux/drivers/char/console.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ -/* - * console.c - * - * This module exports the console io functions: - * - * 'void do_keyboard_interrupt(void)' - * - * 'int vc_allocate(unsigned int console)' - * 'int vc_cons_allocated(unsigned int console)' - * 'int vc_resize(unsigned long lines, unsigned long cols)' - * 'int vc_resize_con(unsigned long lines, unsigned long cols, - * unsigned int currcons)' - * 'void vc_disallocate(unsigned int currcons)' - * - * 'unsigned long con_init(unsigned long)' - * 'int con_open(struct tty_struct *tty, struct file * filp)' - * 'void con_write(struct tty_struct * tty)' - * 'void vt_console_print(const char * b)' - * 'void update_screen(int new_console)' - * - * 'void do_blank_screen(int)' - * 'void do_unblank_screen(void)' - * 'void poke_blanked_console(void)' - * - * 'unsigned short *screen_pos(int currcons, int w_offset, int viewed)' - * 'void complement_pos(int currcons, int offset)' - * 'void invert_screen(int currcons, int offset, int count, int shift)' - * - * 'void scrollback(int lines)' - * 'void scrollfront(int lines)' - * - * 'int con_get_font(char *)' - * 'int con_set_font(char *)' - * - * 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)' - * 'int mouse_reporting(void)' - * - * 'unsigned long get_video_num_lines(unsigned int console)' - * 'unsigned long get_video_num_columns(unsigned int console)' - * 'unsigned long get_video_size_row(unsigned int console)' - * - * Hopefully this will be a rather complete VT102 implementation. - * - * Beeping thanks to John T Kohl. - * - * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics - * Chars, and VT100 enhancements by Peter MacDonald. - * - * Copy and paste function by Andrew Haylett, - * some enhancements by Alessandro Rubini. - * - * User definable mapping table and font loading by Eugene G. Crosser, - * - * - * Code to check for different video-cards mostly by Galen Hunt, - * - * - * Rudimentary ISO 10646/Unicode/UTF-8 character set support by - * Markus Kuhn, . - * - * Dynamic allocation of consoles, aeb@cwi.nl, May 1994 - * Resizing of consoles, aeb, 940926 - * - * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94 - * - * - * 680x0 LINUX support by Arno Griffioen (arno@usn.nl) - * - * 9-Apr-94: Arno Griffioen: fixed scrolling and delete-char bug. - * Scrolling code moved to amicon.c - * - * 18-Apr-94: David Carter [carter@cs.bris.ac.uk]. 680x0 LINUX modified - * Integrated support for new low level driver `amicon_ocs.c' - * - */ - -#define BLANK 0x0020 -#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */ - -/* A bitmap for codes <32. A bit of 1 indicates that the code - * corresponding to that bit number invokes some special action - * (such as cursor movement) and should not be displayed as a - * glyph unless the disp_ctrl mode is explicitly enabled. - */ -#define CTRL_ACTION 0x0d00ff81 -#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */ - -/* - * Here is the default bell parameters: 750HZ, 1/8th of a second - */ -#define DEFAULT_BELL_PITCH 750 -#define DEFAULT_BELL_DURATION (HZ/8) - -/* - * NOTE!!! We sometimes disable and enable interrupts for a short while - * (to put a word in video IO), but this will work even for keyboard - * interrupts. We know interrupts aren't enabled when getting a keyboard - * interrupt, as we use trap-gates. Hopefully all is well. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -struct tty_driver console_driver; -static int console_refcount; -static struct tty_struct *console_table[MAX_NR_CONSOLES]; -static struct termios *console_termios[MAX_NR_CONSOLES]; -static struct termios *console_termios_locked[MAX_NR_CONSOLES]; - -static void vc_init(unsigned int console, int do_clear); - -static void update_attr(int currcons); -static void gotoxy(int currcons, int new_x, int new_y); -static void save_cur(int currcons); -static void blank_screen(void); -static void unblank_screen(void); -static int con_open(struct tty_struct *, struct file *); -extern void change_console(unsigned int); -static inline void set_cursor(int currcons); -static void reset_terminal(int currcons, int do_clear); -extern void reset_vc(unsigned int new_console); -extern void vt_init(void); -static void set_vesa_blanking(unsigned long arg); -extern void vesa_blank(void); -extern void vesa_unblank(void); -extern void compute_shiftstate(void); -extern void reset_palette(int currcons); -extern void set_palette(void); -void poke_blanked_console(void); -void do_blank_screen(int); - -#if 0 -/* Make sure there are no references left to this variables. */ -unsigned long video_num_lines; -unsigned long video_num_columns; -unsigned long video_size_row; -#endif - -static int printable = 0; /* Is console ready for printing? */ -unsigned long video_font_height; /* Height of current screen font */ -unsigned long video_scan_lines; /* Number of scan lines on screen */ -unsigned long default_font_height; /* Height of default screen font */ -int video_mode_512ch = 0; /* 512-character mode */ -static unsigned short console_charmask = 0x0ff; - -static unsigned short *vc_scrbuf[MAX_NR_CONSOLES]; -struct vc vc_cons [MAX_NR_CONSOLES]; - -/* used by kbd_bh - set by keyboard_interrupt */ - int do_poke_blanked_console = 0; - int console_blanked = 0; -static int blankinterval = 10*60*HZ; -static int vesa_off_interval = 0; -static int vesa_blank_mode = 0; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ - -/* - * fg_console is the current virtual console, - * last_console is the last used one, - * want_console is the console we want to switch to, - * kmsg_redirect is the console for kernel messages, - */ -int fg_console = 0; -int last_console = 0; -int want_console = -1; -int kmsg_redirect = 0; - -struct consw *conswitchp; - -#define cols (vc_cons[currcons].d->vc_cols) -#define rows (vc_cons[currcons].d->vc_rows) -#define size_row (vc_cons[currcons].d->vc_size_row) -#define screenbuf_size (vc_cons[currcons].d->vc_screenbuf_size) -#define cons_num (vc_cons[currcons].d->vc_num) -#define origin (vc_cons[currcons].d->vc_origin) -#define scr_end (vc_cons[currcons].d->vc_scr_end) -#define pos (vc_cons[currcons].d->vc_pos) -#define top (vc_cons[currcons].d->vc_top) -#define bottom (vc_cons[currcons].d->vc_bottom) -#define x (vc_cons[currcons].d->vc_x) -#define y (vc_cons[currcons].d->vc_y) -#define vc_state (vc_cons[currcons].d->vc_state) -#define npar (vc_cons[currcons].d->vc_npar) -#define par (vc_cons[currcons].d->vc_par) -#define ques (vc_cons[currcons].d->vc_ques) -#define attr (vc_cons[currcons].d->vc_attr) -#define saved_x (vc_cons[currcons].d->vc_saved_x) -#define saved_y (vc_cons[currcons].d->vc_saved_y) -#define translate (vc_cons[currcons].d->vc_translate) -#define G0_charset (vc_cons[currcons].d->vc_G0_charset) -#define G1_charset (vc_cons[currcons].d->vc_G1_charset) -#define saved_G0 (vc_cons[currcons].d->vc_saved_G0) -#define saved_G1 (vc_cons[currcons].d->vc_saved_G1) -#define utf (vc_cons[currcons].d->vc_utf) -#define utf_count (vc_cons[currcons].d->vc_utf_count) -#define utf_char (vc_cons[currcons].d->vc_utf_char) -#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start) -#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end) -#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char) -#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl) -#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta) -#define decscnm (vc_cons[currcons].d->vc_decscnm) -#define decom (vc_cons[currcons].d->vc_decom) -#define decawm (vc_cons[currcons].d->vc_decawm) -#define deccm (vc_cons[currcons].d->vc_deccm) -#define decim (vc_cons[currcons].d->vc_decim) -#define deccolm (vc_cons[currcons].d->vc_deccolm) -#define need_wrap (vc_cons[currcons].d->vc_need_wrap) -#define has_scrolled (vc_cons[currcons].d->vc_has_scrolled) -#define kmalloced (vc_cons[currcons].d->vc_kmalloced) -#define report_mouse (vc_cons[currcons].d->vc_report_mouse) -#define can_do_color (vc_cons[currcons].d->vc_can_do_color) -#define color (vc_cons[currcons].d->vc_color) -#define s_color (vc_cons[currcons].d->vc_s_color) -#define def_color (vc_cons[currcons].d->vc_def_color) -#define foreground (color & 0x0f) -#define background (color & 0xf0) -#define charset (vc_cons[currcons].d->vc_charset) -#define s_charset (vc_cons[currcons].d->vc_s_charset) -#define intensity (vc_cons[currcons].d->vc_intensity) -#define underline (vc_cons[currcons].d->vc_underline) -#define blink (vc_cons[currcons].d->vc_blink) -#define reverse (vc_cons[currcons].d->vc_reverse) -#define s_intensity (vc_cons[currcons].d->vc_s_intensity) -#define s_underline (vc_cons[currcons].d->vc_s_underline) -#define s_blink (vc_cons[currcons].d->vc_s_blink) -#define s_reverse (vc_cons[currcons].d->vc_s_reverse) -#define ulcolor (vc_cons[currcons].d->vc_ulcolor) -#define halfcolor (vc_cons[currcons].d->vc_halfcolor) -#define tab_stop (vc_cons[currcons].d->vc_tab_stop) -#define palette (vc_cons[currcons].d->vc_palette) -#define bell_pitch (vc_cons[currcons].d->vc_bell_pitch) -#define bell_duration (vc_cons[currcons].d->vc_bell_duration) -#define sw (vc_cons[currcons].d->vc_sw) - -#define vcmode (vt_cons[currcons]->vc_mode) -#if 0 /* XXX */ -#define vtmode (vt_cons[currcons]->vt_mode) -#define vtpid (vt_cons[currcons]->vt_pid) -#define vtnewvt (vt_cons[currcons]->vt_newvt) -#endif - -int vc_cons_allocated(unsigned int i) -{ - return (i < MAX_NR_CONSOLES && vc_cons[i].d); -} - -int vc_allocate(unsigned int currcons) /* return 0 on success */ -{ - if (currcons >= MAX_NR_CONSOLES) - return -ENODEV; - if (!vc_cons[currcons].d) { - long p, q; - - /* prevent users from taking too much memory */ - if (currcons >= MAX_NR_USER_CONSOLES && !suser()) - return -EPERM; - - /* due to the granularity of kmalloc, we waste some memory here */ - /* the alloc is done in two steps, to optimize the common situation - of a 25x80 console (structsize=216, screenbuf_size=4000) */ - p = (long) kmalloc(structsize, GFP_KERNEL); - if (!p) - return -ENOMEM; - vc_cons[currcons].d = (struct vc_data *) p; - vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data)); - - /* ++Geert: sw->con_init determines console size */ - sw = conswitchp; - cons_num = currcons; - sw->con_init (vc_cons[currcons].d); - size_row = cols<<1; - screenbuf_size = rows*size_row; - - q = (long) kmalloc(screenbuf_size, GFP_KERNEL); - if (!q) { - kfree_s((char *) p, structsize); - vc_cons[currcons].d = NULL; - return -ENOMEM; - } - vc_scrbuf[currcons] = (unsigned short *) q; - kmalloced = 1; - vc_init (currcons, 1); - } - return 0; -} - -/* - * Change # of rows and columns (0 means the size of fg_console) - * [this is to be used together with some user program - * like resize that changes the hardware videomode] - */ -int vc_resize(unsigned long lines, unsigned long columns) -{ - unsigned long cc, ll, ss, sr; - unsigned long occ, oll, oss, osr; - unsigned short *p; - unsigned int currcons = fg_console, i; - unsigned short *newscreens[MAX_NR_CONSOLES]; - long ol, nl, rlth, rrem; - - cc = (columns ? columns : cols); - ll = (lines ? lines : rows); - sr = cc << 1; - ss = sr * ll; - - /* - * Some earlier version had all consoles of potentially - * different sizes, but that was really messy. - * So now we only change if there is room for all consoles - * of the same size. - */ - for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { - if (!vc_cons_allocated(currcons)) - newscreens[currcons] = 0; - else { - p = (unsigned short *) kmalloc(ss, GFP_USER); - if (!p) { - for (i = 0; i< currcons; i++) - if (newscreens[i]) - kfree_s(newscreens[i], ss); - return -ENOMEM; - } - newscreens[currcons] = p; - } - } - -#if 0 /* XXX */ - get_scrmem(fg_console); -#endif - - for (currcons = 0; currcons < MAX_NR_CONSOLES; currcons++) { - if (!vc_cons_allocated(currcons)) - continue; - - oll = rows; - occ = cols; - osr = size_row; - oss = screenbuf_size; - - rows = ll; - cols = cc; - size_row = sr; - screenbuf_size = ss; - - rlth = MIN(osr, sr); - rrem = sr - rlth; - ol = origin; - nl = (long) newscreens[currcons]; - if (ll < oll) - ol += (oll - ll) * osr; - - update_attr(currcons); - while (ol < scr_end) { - /* ++Geert: TODO: Because the attributes have different meanings - on monochrome and color, they should really be converted if - can_do_color changes... */ - memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); - if (rrem) - memsetw((void *)(nl + rlth), video_erase_char, rrem); - ol += osr; - nl += sr; - } - - if (kmalloced) - kfree_s(vc_scrbuf[currcons], oss); - vc_scrbuf[currcons] = newscreens[currcons]; - kmalloced = 1; - screenbuf_size = ss; - - origin = (long) video_mem_start = vc_scrbuf[currcons]; - scr_end = video_mem_end = ((long) video_mem_start) + ss; - - if (scr_end > nl) - memsetw((void *) nl, video_erase_char, scr_end - nl); - - /* do part of a reset_terminal() */ - top = 0; - bottom = rows; - gotoxy(currcons, x, y); - save_cur(currcons); - } - -#if 0 /* XXX */ - set_scrmem(fg_console, 0); - set_origin(fg_console); -#endif /* XXX */ - /* don't update in graphics mode */ - if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT) - update_screen(fg_console); - - set_cursor(fg_console); - - return 0; -} - -/* - * ++Geert: Change # of rows and columns for one specific console. - * Of course it's not messy to have all consoles of potentially different sizes, - * except on PCish hardware :-) - * - * This is called by the low level console driver (arch/m68k/console/fbcon.c or - * arch/m68k/console/txtcon.c) - */ -void vc_resize_con(unsigned long lines, unsigned long columns, - unsigned int currcons) -{ - unsigned long cc, ll, ss, sr; - unsigned long occ, oll, oss, osr; - unsigned short *newscreen; - long ol, nl, rlth, rrem; - struct winsize ws; - - if (!columns || !lines || currcons >= MAX_NR_CONSOLES) - return; - - cc = columns; - ll = lines; - sr = cc << 1; - ss = sr * ll; - - if (!vc_cons_allocated(currcons)) - newscreen = 0; - else if (!(newscreen = (unsigned short *) kmalloc(ss, GFP_USER))) - return; - - if (vc_cons_allocated(currcons)) { - oll = rows; - occ = cols; - osr = size_row; - oss = screenbuf_size; - - rows = ll; - cols = cc; - size_row = sr; - screenbuf_size = ss; - - rlth = MIN(osr, sr); - rrem = sr - rlth; - ol = origin; - nl = (long) newscreen; - if (ll < oll) - ol += (oll - ll) * osr; - - update_attr(currcons); - while (ol < scr_end) { - /* ++Geert: TODO: Because the attributes have different meanings - on monochrome and color, they should really be converted if - can_do_color changes... */ - memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth); - if (rrem) - memsetw((void *)(nl + rlth), video_erase_char, rrem); - ol += osr; - nl += sr; - } - - if (kmalloced) - kfree_s(vc_scrbuf[currcons], oss); - vc_scrbuf[currcons] = newscreen; - kmalloced = 1; - screenbuf_size = ss; - - origin = (long) video_mem_start = vc_scrbuf[currcons]; - scr_end = video_mem_end = ((long)video_mem_start) + ss; - - if (scr_end > nl) - memsetw((void *) nl, video_erase_char, scr_end - nl); - - /* do part of a reset_terminal() */ - top = 0; - bottom = rows; - gotoxy(currcons, x, y); - save_cur(currcons); - - ws.ws_row = rows; - ws.ws_col = cols; - if (memcmp(&ws, &console_table[currcons]->winsize, sizeof (struct winsize)) && - console_table[currcons]->pgrp > 0) - kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1); - console_table[currcons]->winsize = ws; - } - - /* don't update in graphics mode */ - if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT) - update_screen(fg_console); -} - -void vc_disallocate(unsigned int currcons) -{ - if (vc_cons_allocated(currcons)) { - if (kmalloced) - kfree_s(vc_scrbuf[currcons], screenbuf_size); - if (currcons >= MIN_NR_CONSOLES) - kfree_s(vc_cons[currcons].d, structsize); - vc_cons[currcons].d = 0; - } -} - - -#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x) -#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x) -#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x) - -#define decarm VC_REPEAT -#define decckm VC_CKMODE -#define kbdapplic VC_APPLIC -#define lnm VC_CRLF - -/* - * this is what the terminal answers to a ESC-Z or csi0c query. - */ -#define VT100ID "\033[?1;2c" -#define VT102ID "\033[?6c" - -static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, - 8,12,10,14, 9,13,11,15 }; - -/* the default colour table, for VGA+ colour systems */ -int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa, - 0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff}; -int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa, - 0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff}; -int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa, - 0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff}; - -/* - * gotoxy() must verify all boundaries, because the arguments - * might also be negative. If the given position is out of - * bounds, the cursor is placed at the nearest margin. - */ -static void gotoxy(int currcons, int new_x, int new_y) -{ - int min_y, max_y; - - if (new_x < 0) - x = 0; - else - if (new_x >= cols) - x = cols - 1; - else - x = new_x; - if (decom) { - min_y = top; - max_y = bottom; - } else { - min_y = 0; - max_y = rows; - } - if (new_y < min_y) - y = min_y; - else if (new_y >= max_y) - y = max_y - 1; - else - y = new_y; - pos = video_mem_start + y * cols + x; - need_wrap = 0; -} - -/* for absolute user moves, when decom is set */ -static void gotoxay(int currcons, int new_x, int new_y) -{ - gotoxy(currcons, new_x, decom ? (top+new_y) : new_y); -} - -static void hide_cursor(int currcons) -{ - sw->con_cursor(vc_cons[currcons].d,CM_ERASE); - return; -} - -static void set_cursor(int currcons) -{ - if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) - return; - if (deccm) - sw->con_cursor(vc_cons[currcons].d,CM_DRAW); - else - hide_cursor(currcons); - return; -} - -void no_scroll(char *str, int *ints) -{ - /* - * no_scroll currently does nothing on the m68k. - */ -} - -/* - * Arno: - * Why do we need these? The keyboard code doesn't seem to do anything - * with them either... - */ -void scrollfront(int l) -{ - return; -} - -void scrollback(int l) -{ - return; -} - -static void scrup(int currcons, unsigned int t, unsigned int b, int nr) -{ - unsigned short *p; - int i; - - if (b > rows || t >= b) - return; - - memmove (video_mem_start + t * cols, - video_mem_start + (t + nr) * cols, - (b - t - nr) * cols * 2); - - p = video_mem_start + (b - nr) * cols; - for (i = nr * cols; i > 0; i--) - *p++ = video_erase_char; - - if (currcons != fg_console) - return; -/* - * Arno: - * Scrolling has now been moved to amicon.c where it should have - * been all along. - */ - sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr); - - return; - -} - -static void scrdown(int currcons, unsigned int t, unsigned int b, - int nr) -{ - unsigned short *p; - int i; - - if (b > rows || t >= b) - return; - - memmove (video_mem_start + (t + nr) * cols, - video_mem_start + t * cols, - (b - t - nr) * cols * 2); - - p = video_mem_start + t * cols; - for (i = nr * cols; i > 0; i--) - *p++ = video_erase_char; - - if (currcons != fg_console) - return; -/* - * Arno: - * Scrolling has now been moved to amicon.c where it should have - * been all along. - */ - sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr); - - return; -} - -static void lf(int currcons) -{ - /* don't scroll if above bottom of scrolling region, or - * if below scrolling region - */ - if (y+1 == bottom) - scrup(currcons,top,bottom, 1); - else if (y < rows-1) { - y++; - pos += cols; - } - need_wrap = 0; -} - -static void ri(int currcons) -{ - /* don't scroll if below top of scrolling region, or - * if above scrolling region - */ - if (y == top) - scrdown(currcons,top,bottom, 1); - else if (y > 0) { - y--; - pos -= cols; - } - need_wrap = 0; -} - -static inline void cr(int currcons) -{ - pos -= x; - need_wrap = x = 0; -} - -static inline void bs(int currcons) -{ - if (x) { - pos--; - x--; - need_wrap = 0; - } -} - -static inline void del(int currcons) -{ - /* ignored */ -} - -static void csi_J(int currcons, int vpar) -{ - unsigned long count; - unsigned short *start; - - switch (vpar) { - case 0: /* erase from cursor to end of display */ - count = (video_mem_start - + cols * rows - - pos); - start = pos; - if (currcons != fg_console) - break; - /* 680x0 do in two stages */ - sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x); - sw->con_clear(vc_cons[currcons].d,y+1,0,rows-y-1, cols); - break; - case 1: /* erase from start to cursor */ - count = pos - video_mem_start + 1; - start = video_mem_start; - if (currcons != fg_console) - break; - /* 680x0 do in two stages */ - sw->con_clear(vc_cons[currcons].d,0,0,y, cols); - sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1); - break; - case 2: /* erase whole display */ - count = cols * rows; - start = video_mem_start; - if (currcons != fg_console) - break; - sw->con_clear(vc_cons[currcons].d,0,0,rows, cols); - break; - default: - return; - } - while (count-- > 0) - *start++ = video_erase_char; - need_wrap = 0; -} - -static void csi_K(int currcons, int vpar) -{ - unsigned long count; - unsigned short *start; - - switch (vpar) { - case 0: /* erase from cursor to end of line */ - count = cols - x; - start = pos; - if (currcons != fg_console) - break; - sw->con_clear(vc_cons[currcons].d,y,x,1,cols-x); - break; - case 1: /* erase from start of line to cursor */ - start = pos - x; - count = x + 1; - if (currcons != fg_console) - break; - sw->con_clear(vc_cons[currcons].d,y,0,1,x + 1); - break; - case 2: /* erase whole line */ - start = pos - x; - count = cols; - if (currcons != fg_console) - break; - sw->con_clear(vc_cons[currcons].d,y,0,1,cols); - break; - default: - return; - } - while (count-- > 0) - *start++ = video_erase_char; - need_wrap = 0; -} - -static void csi_X(int currcons, int vpar) /* erase the following vpar positions */ -{ /* not vt100? */ - unsigned long count; - unsigned short * start; - - if (!vpar) - vpar++; - - start = pos; - count = (vpar > cols-x) ? (cols-x) : vpar; - - if (currcons == fg_console) - sw->con_clear(vc_cons[currcons].d,y,x,1,count); - - while (count-- > 0) - *start++ = video_erase_char; - need_wrap = 0; -} - -/* - * Arno: - * On 680x0 attributes are currently not used. This piece of code - * seems hardware independent, but uses the EGA/VGA way of representing - * attributes. - * TODO: modify for 680x0 and add attribute processing to putc code. - * - * ++roman: I completely changed the attribute format for monochrome - * mode (!can_do_color). The formerly used MDA (monochrome display - * adapter) format didn't allow the combination of certain effects. - * Now the attribute is just a bit vector: - * Bit 0..1: intensity (0..2) - * Bit 2 : underline - * Bit 3 : reverse - * Bit 7 : blink - */ -static void update_attr(int currcons) -{ - if (!can_do_color) { - /* Special treatment for monochrome */ - attr = intensity | - (underline ? 4 : 0) | - ((reverse ^ decscnm) ? 8 : 0) | - (blink ? 0x80 : 0); - video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0); - return; - } - - attr = color; - if (underline) - attr = (attr & 0xf0) | ulcolor; - else if (intensity == 0) - attr = (attr & 0xf0) | halfcolor; - if (reverse ^ decscnm) - attr = reverse_video_char(attr); - if (blink) - attr ^= 0x80; - if (intensity == 2) - attr ^= 0x08; - if (decscnm) - video_erase_char = (reverse_video_char(color) << 8) | ' '; - else - video_erase_char = (color << 8) | ' '; -} - -static void default_attr(int currcons) -{ - intensity = 1; - underline = 0; - reverse = 0; - blink = 0; - color = def_color; -} - -static void csi_m(int currcons) -{ - int i; - - for (i=0;i<=npar;i++) - switch (par[i]) { - case 0: /* all attributes off */ - default_attr(currcons); - break; - case 1: - intensity = 2; - break; - case 2: - intensity = 0; - break; - case 4: - underline = 1; - break; - case 5: - blink = 1; - break; - case 7: - reverse = 1; - break; - case 10: /* ANSI X3.64-1979 (SCO-ish?) - * Select primary font, don't display - * control chars if defined, don't set - * bit 8 on output. - */ - translate = set_translate(charset == 0 - ? G0_charset - : G1_charset); - disp_ctrl = 0; - toggle_meta = 0; - break; - case 11: /* ANSI X3.64-1979 (SCO-ish?) - * Select first alternate font, let's - * chars < 32 be displayed as ROM chars. - */ - translate = set_translate(IBMPC_MAP); - disp_ctrl = 1; - toggle_meta = 0; - break; - case 12: /* ANSI X3.64-1979 (SCO-ish?) - * Select second alternate font, toggle - * high bit before displaying as ROM char. - */ - translate = set_translate(IBMPC_MAP); - disp_ctrl = 1; - toggle_meta = 1; - break; - case 21: - case 22: - intensity = 1; - break; - case 24: - underline = 0; - break; - case 25: - blink = 0; - break; - case 27: - reverse = 0; - break; - case 38: /* ANSI X3.64-1979 (SCO-ish?) - * Enables underscore, white foreground - * with white underscore (Linux - use - * default foreground). - */ - color = (def_color & 0x0f) | background; - underline = 1; - break; - case 39: /* ANSI X3.64-1979 (SCO-ish?) - * Disable underline option. - * Reset colour to default? It did this - * before... - */ - color = (def_color & 0x0f) | background; - underline = 0; - break; - case 49: - color = (def_color & 0xf0) | foreground; - break; - default: - if (par[i] >= 30 && par[i] <= 37) - color = color_table[par[i]-30] - | background; - else if (par[i] >= 40 && par[i] <= 47) - color = (color_table[par[i]-40]<<4) - | foreground; - break; - } - update_attr(currcons); -} - -static void respond_string(const char * p, struct tty_struct * tty) -{ - while (*p) { - tty_insert_flip_char(tty, *p, 0); - p++; - } - tty_schedule_flip(tty); -} - -static inline void cursor_report(int currcons, struct tty_struct * tty) -{ - char buf[40]; - - sprintf(buf, "\033[%ld;%ldR", y + (decom ? top+1 : 1), x+1); - respond_string(buf, tty); -} - -static inline void status_report(struct tty_struct * tty) -{ - respond_string("\033[0n", tty); /* Terminal ok */ -} - -static inline void respond_ID(struct tty_struct * tty) -{ - respond_string(VT102ID, tty); -} - -void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry) -{ - char buf[8]; - - sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx), - (char)('!' + mry)); - respond_string(buf, tty); -} - -/* invoked via ioctl(TIOCLINUX) and through set_selection */ -int mouse_reporting(void) -{ - int currcons = fg_console; - - return report_mouse; -} - -int tioclinux(struct tty_struct *tty, unsigned long arg) -{ - char type, data; - - if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE) - return -EINVAL; - if (current->tty != tty && !suser()) - return -EPERM; - if (get_user(type, (char *)arg)) - return -EFAULT; - switch (type) - { - case 2: - return set_selection(arg, tty, 1); - case 3: - return paste_selection(tty); - case 4: - do_unblank_screen(); - return 0; - case 5: - return sel_loadlut(arg); - case 6: - - /* - * Make it possible to react to Shift+Mousebutton. - * Note that 'shift_state' is an undocumented - * kernel-internal variable; programs not closely - * related to the kernel should not use this. - */ - data = shift_state; - return put_user(data, (char *) arg); - case 7: - data = mouse_reporting(); - return put_user(data, (char *) arg); - case 10: - set_vesa_blanking(arg); - return 0; - case 11: /* set kmsg redirect */ - if (!suser()) - return -EPERM; - if (get_user(data, (char *)arg+1)) - return -EFAULT; - kmsg_redirect = data; - return 0; - case 12: /* get fg_console */ - return fg_console; - } - return -EINVAL; -} - -static inline unsigned short *screenpos(int currcons, int offset, int viewed) -{ - unsigned short *p = (unsigned short *)(origin + offset); -#if 0 - if (viewed && currcons == fg_console) - p -= (__real_origin - __origin); -#endif - return p; -} - -/* Note: inverting the screen twice should revert to the original state */ -void invert_screen(int currcons, int offset, int count, int viewed) -{ - unsigned short *p; - unsigned short xx, yy, oldattr; - - count /= 2; - p = screenpos(currcons, offset, viewed); - xx = (offset >> 1) % cols; - yy = (offset >> 1) / cols; - oldattr = attr; - if (can_do_color) - while (count--) { - unsigned short old = scr_readw(p); - unsigned short new = reverse_video_short(old); - scr_writew(new, p); - p++; - if (currcons != fg_console) - continue; - attr = new >> 8; - sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx); - if (++xx == cols) - xx = 0, ++yy; - } - else - while (count--) { - unsigned short old = scr_readw(p); - unsigned short new = old ^ 0x800; - scr_writew(new, p); - p++; - if (currcons != fg_console) - continue; - attr = new >> 8; - sw->con_putc(vc_cons[currcons].d, new & 0xff, yy, xx); - if (++xx == cols) - xx = 0, ++yy; - } - attr = oldattr; -} - -/* used by selection: complement pointer position */ -void complement_pos(int currcons, int offset) -{ - static unsigned short *p = NULL; - static unsigned short old = 0; - static unsigned short oldx = 0, oldy = 0; - unsigned short new, oldattr; - - oldattr = attr; - if (p) { - scr_writew(old, p); - if (currcons == fg_console) { - attr = old >> 8; - sw->con_putc(vc_cons[currcons].d, old & 0xff, oldy, oldx); - attr = oldattr; - } - } - if (offset == -1) - p = NULL; - else { - p = screenpos(currcons, offset, 1); - old = scr_readw(p); - oldx = (offset >> 1) % cols; - oldy = (offset >> 1) / cols; - if (can_do_color) - new = old ^ 0x7700; - else - new = old ^ 0x800; - scr_writew(new, p); - if (currcons == fg_console) { - attr = new >> 8; - sw->con_putc(vc_cons[currcons].d, new & 0xff, oldy, oldx); - attr = oldattr; - } - } -} - -/* used by selection */ -unsigned short screen_word(int currcons, int offset, int viewed) -{ - return scr_readw(screenpos(currcons, offset, viewed)); -} - -/* used by selection - convert a screen word to a glyph number */ -int scrw2glyph(unsigned short scr_word) -{ - return ( video_mode_512ch ) - ? ((scr_word & 0x0800) >> 3) + (scr_word & 0x00ff) - : scr_word & 0x00ff; -} - -/* used by vcs - note the word offset */ -unsigned short *screen_pos(int currcons, int w_offset, int viewed) -{ - return screenpos(currcons, 2 * w_offset, viewed); -} - -void getconsxy(int currcons, char *p) -{ - p[0] = x; - p[1] = y; -} - -void putconsxy(int currcons, char *p) -{ - gotoxy(currcons, p[0], p[1]); - set_cursor(currcons); -} - -static void set_mode(int currcons, int on_off) -{ - int i; - - for (i=0; i<=npar; i++) - if (ques) switch(par[i]) { /* DEC private modes set/reset */ - case 1: /* Cursor keys send ^[Ox/^[[x */ - if (on_off) - set_kbd(decckm); - else - clr_kbd(decckm); - break; - case 3: /* 80/132 mode switch unimplemented */ - deccolm = on_off; -#if 0 - (void) vc_resize(rows, deccolm ? 132 : 80); - /* this alone does not suffice; some user mode - utility has to change the hardware regs */ -#endif - break; - case 5: /* Inverted screen on/off */ - if (decscnm != on_off) { - decscnm = on_off; - invert_screen(currcons, 0, screenbuf_size, 0); - update_attr(currcons); - } - break; - case 6: /* Origin relative/absolute */ - decom = on_off; - gotoxay(currcons,0,0); - break; - case 7: /* Autowrap on/off */ - decawm = on_off; - break; - case 8: /* Autorepeat on/off */ - if (on_off) - set_kbd(decarm); - else - clr_kbd(decarm); - break; - case 9: - report_mouse = on_off ? 1 : 0; - break; - case 25: /* Cursor on/off */ - deccm = on_off; - set_cursor(currcons); - break; - case 1000: - report_mouse = on_off ? 2 : 0; - break; - } else switch(par[i]) { /* ANSI modes set/reset */ - case 3: /* Monitor (display ctrls) */ - disp_ctrl = on_off; - break; - case 4: /* Insert Mode on/off */ - decim = on_off; - break; - case 20: /* Lf, Enter == CrLf/Lf */ - if (on_off) - set_kbd(lnm); - else - clr_kbd(lnm); - break; - } -} - -static void setterm_command(int currcons) -{ - switch(par[0]) { - case 1: /* set color for underline mode */ - if (can_do_color && par[1] < 16) { - ulcolor = color_table[par[1]]; - if (underline) - update_attr(currcons); - } - break; - case 2: /* set color for half intensity mode */ - if (can_do_color && par[1] < 16) { - halfcolor = color_table[par[1]]; - if (intensity == 0) - update_attr(currcons); - } - break; - case 8: /* store colors as defaults */ - def_color = attr; - default_attr(currcons); - update_attr(currcons); - break; - case 9: /* set blanking interval */ - blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; - poke_blanked_console(); - break; - case 10: /* set bell frequency in Hz */ - if (npar >= 1) - bell_pitch = par[1]; - else - bell_pitch = DEFAULT_BELL_PITCH; - break; - case 11: /* set bell duration in msec */ - if (npar >= 1) - bell_duration = (par[1] < 2000) ? - par[1]*HZ/1000 : 0; - else - bell_duration = DEFAULT_BELL_DURATION; - break; - case 12: /* bring specified console to the front */ - if (par[1] >= 1 && vc_cons_allocated(par[1]-1)) - update_screen(par[1]-1); - break; - case 13: /* unblank the screen */ - unblank_screen(); - break; - case 14: /* set vesa powerdown interval */ - vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; - break; - } -} - -static inline void insert_char(int currcons) -{ - int i; - unsigned short *p = pos; - - for (i = cols - x - 2; i >= 0; i--) - p[i + 1] = p[i]; - *pos = video_erase_char; - need_wrap = 0; - - if (currcons != fg_console) - return; - - /* Arno: - * Move the remainder of the line (-1 character) one spot to the right - */ - sw->con_bmove(vc_cons[currcons].d,y,x,y,x+1,1,(cols-x-1)); - /* - * Print the erase char on the current position - */ - sw->con_putc(vc_cons[currcons].d,(video_erase_char & 0x00ff),y,x); -} - -static void csi_at(int currcons, unsigned int nr) -{ - int i; - unsigned short *p; - - if (nr > cols - x) - nr = cols - x; - else if (!nr) - nr = 1; - - p = pos + cols - x - nr; - while (--p >= pos) - p[nr] = *p; - for (i = 0; i < nr; i++) - *++p = video_erase_char; - need_wrap = 0; - - if (currcons != fg_console) - return; - - sw->con_bmove (vc_cons[currcons].d, y, x, y, x + nr, - 1, cols - x - nr); - while (nr--) - sw->con_putc (vc_cons[currcons].d, - video_erase_char & 0x00ff, y, x + nr); -} - -static void csi_L(int currcons, unsigned int nr) -{ - if (nr > rows) - nr = rows; - else if (!nr) - nr = 1; - scrdown (currcons, y, bottom, nr); - need_wrap = 0; -} - -static void csi_P(int currcons, unsigned int nr) -{ - int i; - unsigned short *p, *end; - - if (nr > cols - x) - nr = cols - x; - else if (!nr) - nr = 1; - - p = pos; - end = pos + cols - x - nr; - while (p < end) - *p = p[nr], p++; - for (i = 0; i < nr; i++) - *p++ = video_erase_char; - need_wrap = 0; - - if (currcons != fg_console) - return; - - sw->con_bmove (vc_cons[currcons].d, y, x + nr, y, x, - 1, cols - x - nr); - - while (nr--) - sw->con_putc (vc_cons[currcons].d, video_erase_char & 0x00ff, - y, cols - 1 - nr); -} - -static void csi_M(int currcons, unsigned int nr) -{ - if (nr > rows) - nr = rows; - else if (!nr) - nr=1; - scrup (currcons, y, bottom, nr); - need_wrap = 0; -} - -static void save_cur(int currcons) -{ - saved_x = x; - saved_y = y; - s_intensity = intensity; - s_underline = underline; - s_blink = blink; - s_reverse = reverse; - s_charset = charset; - s_color = color; - saved_G0 = G0_charset; - saved_G1 = G1_charset; -} - -static void restore_cur(int currcons) -{ - gotoxy(currcons,saved_x,saved_y); - intensity = s_intensity; - underline = s_underline; - blink = s_blink; - reverse = s_reverse; - charset = s_charset; - color = s_color; - G0_charset = saved_G0; - G1_charset = saved_G1; - translate = set_translate(charset ? G1_charset : G0_charset); - update_attr(currcons); - need_wrap = 0; -} - -enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, - EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd, - ESpalette }; - -static void reset_terminal(int currcons, int do_clear) -{ - top = 0; - bottom = rows; - vc_state = ESnormal; - ques = 0; - translate = set_translate(LAT1_MAP); - G0_charset = LAT1_MAP; - G1_charset = GRAF_MAP; - charset = 0; - need_wrap = 0; - report_mouse = 0; - utf = 0; - utf_count = 0; - - disp_ctrl = 0; - toggle_meta = 0; - - decscnm = 0; - decom = 0; - decawm = 1; - deccm = 1; - decim = 0; - - set_kbd(decarm); - clr_kbd(decckm); - clr_kbd(kbdapplic); - clr_kbd(lnm); - kbd_table[currcons].lockstate = 0; - kbd_table[currcons].slockstate = 0; - kbd_table[currcons].ledmode = LED_SHOW_FLAGS; - kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate; - set_leds(); - - default_attr(currcons); - update_attr(currcons); - - tab_stop[0] = 0x01010100; - tab_stop[1] = - tab_stop[2] = - tab_stop[3] = - tab_stop[4] = 0x01010101; - - bell_pitch = DEFAULT_BELL_PITCH; - bell_duration = DEFAULT_BELL_DURATION; - - gotoxy(currcons,0,0); - save_cur(currcons); - if (do_clear) - csi_J(currcons,2); -} - -/* - * Turn the Scroll-Lock LED on when the tty is stopped - */ -static void con_stop(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = MINOR(tty->device) - (tty->driver.minor_start); - if (!vc_cons_allocated(console_num)) - return; - set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -/* - * Turn the Scroll-Lock LED off when the console is started - */ -static void con_start(struct tty_struct *tty) -{ - int console_num; - if (!tty) - return; - console_num = MINOR(tty->device) - (tty->driver.minor_start); - if (!vc_cons_allocated(console_num)) - return; - clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); - set_leds(); -} - -static void con_flush_chars(struct tty_struct *tty) -{ - unsigned int currcons; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; - - currcons = vt->vc_num; - if (vcmode != KD_GRAPHICS) - set_cursor(currcons); -} - -static int do_con_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int c, tc, ok, n = 0; - unsigned int currcons; - struct vt_struct *vt = (struct vt_struct *)tty->driver_data; - - currcons = vt->vc_num; - if (!vc_cons_allocated(currcons)) { - /* could this happen? */ - static int error = 0; - if (!error) { - error = 1; - printk("con_write: tty %d not allocated\n", currcons+1); - } - return 0; - } - - /* undraw cursor first */ - if (currcons == fg_console) - hide_cursor(currcons); - - /* clear the selection */ - if (currcons == sel_cons) - clear_selection(); - - disable_bh(CONSOLE_BH); - while (count) { - enable_bh(CONSOLE_BH); - if (from_user) - get_user(c, buf); - else - c = *buf; - buf++; n++; count--; - disable_bh(CONSOLE_BH); - - if (utf) { - /* Combine UTF-8 into Unicode */ - /* Incomplete characters silently ignored */ - if(c > 0x7f) { - if (utf_count > 0 && (c & 0xc0) == 0x80) { - utf_char = (utf_char << 6) | (c & 0x3f); - utf_count--; - if (utf_count == 0) - tc = c = utf_char; - else continue; - } else { - if ((c & 0xe0) == 0xc0) { - utf_count = 1; - utf_char = (c & 0x1f); - } else if ((c & 0xf0) == 0xe0) { - utf_count = 2; - utf_char = (c & 0x0f); - } else if ((c & 0xf8) == 0xf0) { - utf_count = 3; - utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - utf_count = 4; - utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - utf_count = 5; - utf_char = (c & 0x01); - } else - utf_count = 0; - continue; - } - } else { - tc = c; - utf_count = 0; - } - } else { /* no utf */ - tc = translate[toggle_meta ? (c|0x80) : c]; - } - - /* If the original code was a control character we - * only allow a glyph to be displayed if the code is - * not normally used (such as for cursor movement) or - * if the disp_ctrl mode has been explicitly enabled. - * Certain characters (as given by the CTRL_ALWAYS - * bitmap) are always displayed as control characters, - * as the console would be pretty useless without - * them; to display an arbitrary font position use the - * direct-to-font zone in UTF-8 mode. - */ - ok = tc && (c >= 32 || - (!utf && !(((disp_ctrl ? CTRL_ALWAYS - : CTRL_ACTION) >> c) & 1))) - && (c != 127 || disp_ctrl) - && (c != 128+27); - - if (vc_state == ESnormal && ok) { - /* Now try to find out how to display it */ - tc = conv_uni_to_pc(tc); - if ( tc == -4 ) { - /* If we got -4 (not found) then see if we have - defined a replacement character (U+FFFD) */ - tc = conv_uni_to_pc(0xfffd); - } else if ( tc == -3 ) { - /* Bad hash table -- hope for the best */ - tc = c; - } - if (tc & ~console_charmask) - continue; /* Conversion failed */ - - if (need_wrap) { - cr(currcons); - lf(currcons); - } - -#if 1 /* XXX */ - /* DPC: 1994-04-12 - * Speed up overstrike mode, using new putcs. - * - * P.S. I hate 8 spaces per tab! Use Emacs! - */ - - /* Only use this for the foreground console, - where we really draw the chars */ - - if (count > 2 && - !decim && !utf && currcons == fg_console) { - static char putcs_buf[256]; - char *p = putcs_buf; - int putcs_count = 1; - ushort nextx = x + 1; - - *p++ = tc; - *pos++ = tc | (attr << 8); - - if (nextx == cols) { - sw->con_putc(vc_cons[currcons].d, - *putcs_buf, y, x); - pos--; - need_wrap = decawm; - continue; - } - - while (count) - { - enable_bh(CONSOLE_BH); - if (from_user) - get_user(c, buf); - else - c = *buf; - disable_bh(CONSOLE_BH); - tc = translate[toggle_meta ? (c|0x80) : c]; - if (!tc || - !(c >= 32 - || !(((disp_ctrl ? CTRL_ALWAYS - : CTRL_ACTION) >> c) & 1))) - break; - tc = conv_uni_to_pc(tc); - if (tc == -4) - tc = conv_uni_to_pc(0xfffd); - else if (tc == -3) - tc = c; - - buf++; n++; count--; - if (tc & ~console_charmask) - continue; /* Conversion failed */ - - *p++ = tc; - *pos++ = tc | (attr << 8); - ++putcs_count; - ++nextx; - if (nextx == cols || - putcs_count == sizeof (putcs_buf)) - break; - } - - sw->con_putcs(vc_cons[currcons].d, - putcs_buf, putcs_count, y, x); - if (nextx == cols) { - pos--; - x = cols-1; - need_wrap = decawm; - } else - x += putcs_count; - continue; - } - - /* DPC: End of putcs support */ -#endif - - if (decim) - insert_char(currcons); - *pos = (attr << 8) + tc; - if (currcons == fg_console) - sw->con_putc(vc_cons[currcons].d,tc,y,x); - if (x == cols - 1) - need_wrap = decawm; - else { - pos++; - x++; - } - continue; - } - - /* - * Control characters can be used in the _middle_ - * of an escape sequence. - */ - switch (c) { - case 0: - continue; - case 7: - if (bell_duration) - kd_mksound(bell_pitch, bell_duration); - continue; - case 8: - bs(currcons); - continue; - case 9: - pos -= x; - while (x < cols - 1) { - x++; - if (tab_stop[x >> 5] & (1 << (x & 31))) - break; - } - pos += x; - continue; - case 10: case 11: case 12: - lf(currcons); - if (!is_kbd(lnm)) - continue; - case 13: - cr(currcons); - continue; - case 14: - charset = 1; - translate = set_translate(G1_charset); - disp_ctrl = 1; - continue; - case 15: - charset = 0; - translate = set_translate(G0_charset); - disp_ctrl = 0; - continue; - case 24: case 26: - vc_state = ESnormal; - continue; - case 27: - vc_state = ESesc; - continue; - case 127: - del(currcons); - continue; - case 128+27: - vc_state = ESsquare; - continue; - } - switch(vc_state) { - case ESesc: - vc_state = ESnormal; - switch (c) { - case '[': - vc_state = ESsquare; - continue; - case ']': - vc_state = ESnonstd; - continue; - case '%': - vc_state = ESpercent; - continue; - case 'E': - cr(currcons); - lf(currcons); - continue; - case 'M': - ri(currcons); - continue; - case 'D': - lf(currcons); - continue; - case 'H': - tab_stop[x >> 5] |= (1 << (x & 31)); - continue; - case 'Z': - respond_ID(tty); - continue; - case '7': - save_cur(currcons); - continue; - case '8': - restore_cur(currcons); - continue; - case '(': - vc_state = ESsetG0; - continue; - case ')': - vc_state = ESsetG1; - continue; - case '#': - vc_state = EShash; - continue; - case 'c': - reset_terminal(currcons,1); - continue; - case '>': /* Numeric keypad */ - clr_kbd(kbdapplic); - continue; - case '=': /* Appl. keypad */ - set_kbd(kbdapplic); - continue; - } - continue; - case ESnonstd: - if (c=='P') { /* palette escape sequence */ - for (npar=0; npar='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { - par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ; - if (npar==7) { - int i = par[0]*3, j = 1; - palette[i] = 16*par[j++]; - palette[i++] += par[j++]; - palette[i] = 16*par[j++]; - palette[i++] += par[j++]; - palette[i] = 16*par[j++]; - palette[i] += par[j]; - set_palette() ; - vc_state = ESnormal; - } - } else - vc_state = ESnormal; - continue; - case ESsquare: - for(npar = 0 ; npar < NPAR ; npar++) - par[npar] = 0; - npar = 0; - vc_state = ESgetpars; - if (c == '[') { /* Function key */ - vc_state=ESfunckey; - continue; - } - ques = (c=='?'); - if (ques) - continue; - case ESgetpars: - if (c==';' && npar='0' && c<='9') { - par[npar] *= 10; - par[npar] += c-'0'; - continue; - } else vc_state=ESgotpars; - case ESgotpars: - vc_state = ESnormal; - switch(c) { - case 'h': - set_mode(currcons,1); - continue; - case 'l': - set_mode(currcons,0); - continue; - case 'n': - if (!ques) - if (par[0] == 5) - status_report(tty); - else if (par[0] == 6) - cursor_report(currcons,tty); - continue; - } - if (ques) { - ques = 0; - continue; - } - switch(c) { - case 'G': case '`': - if (par[0]) par[0]--; - gotoxy(currcons,par[0],y); - continue; - case 'A': - if (!par[0]) par[0]++; - gotoxy(currcons,x,y-par[0]); - continue; - case 'B': case 'e': - if (!par[0]) par[0]++; - gotoxy(currcons,x,y+par[0]); - continue; - case 'C': case 'a': - if (!par[0]) par[0]++; - gotoxy(currcons,x+par[0],y); - continue; - case 'D': - if (!par[0]) par[0]++; - gotoxy(currcons,x-par[0],y); - continue; - case 'E': - if (!par[0]) par[0]++; - gotoxy(currcons,0,y+par[0]); - continue; - case 'F': - if (!par[0]) par[0]++; - gotoxy(currcons,0,y-par[0]); - continue; - case 'd': - if (par[0]) par[0]--; - gotoxay(currcons,x,par[0]); - continue; - case 'H': case 'f': - if (par[0]) par[0]--; - if (par[1]) par[1]--; - gotoxay(currcons,par[1],par[0]); - continue; - case 'J': - csi_J(currcons,par[0]); - continue; - case 'K': - csi_K(currcons,par[0]); - continue; - case 'L': - csi_L(currcons,par[0]); - continue; - case 'M': - csi_M(currcons,par[0]); - continue; - case 'P': - csi_P(currcons,par[0]); - continue; - case 'c': - if (!par[0]) - respond_ID(tty); - continue; - case 'g': - if (!par[0]) - tab_stop[x >> 5] &= ~(1 << (x & 31)); - else if (par[0] == 3) { - tab_stop[0] = - tab_stop[1] = - tab_stop[2] = - tab_stop[3] = - tab_stop[4] = 0; - } - continue; - case 'm': - csi_m(currcons); - continue; - case 'q': /* DECLL - but only 3 leds */ - /* map 0,1,2,3 to 0,1,2,4 */ - if (par[0] < 4) - setledstate(kbd_table + currcons, - (par[0] < 3) ? par[0] : 4); - continue; - case 'r': - if (!par[0]) - par[0]++; - if (!par[1]) - par[1] = rows; - /* Minimum allowed region is 2 lines */ - if (par[0] < par[1] && - par[1] <= rows) { - top=par[0]-1; - bottom=par[1]; - gotoxay(currcons,0,0); - } - continue; - case 's': - save_cur(currcons); - continue; - case 'u': - restore_cur(currcons); - continue; - case 'X': - csi_X(currcons, par[0]); - continue; - case '@': - csi_at(currcons,par[0]); - continue; - case ']': /* setterm functions */ - setterm_command(currcons); - continue; - } - continue; - case ESpercent: - vc_state = ESnormal; - switch (c) { - case '@': /* defined in ISO 2022 */ - utf = 0; - continue; - case 'G': /* prelim official escape code */ - case '8': /* retained for compatibility */ - utf = 1; - continue; - } - continue; - case ESfunckey: - vc_state = ESnormal; - continue; - case EShash: - vc_state = ESnormal; - if (c == '8') { - /* DEC screen alignment test. kludge :-) */ - video_erase_char = - (video_erase_char & 0xff00) | 'E'; - /* Arno: - * Doesn't work, because csi_J(c,2) - * calls con_clear and doesn't print - * the erase char.. - */ - csi_J(currcons, 2); - video_erase_char = - (video_erase_char & 0xff00) | ' '; - } - continue; - case ESsetG0: - if (c == '0') - G0_charset = GRAF_MAP; - else if (c == 'B') - G0_charset = LAT1_MAP; - else if (c == 'U') - G0_charset = IBMPC_MAP; - else if (c == 'K') - G0_charset = USER_MAP; - if (charset == 0) - translate = set_translate(G0_charset); - vc_state = ESnormal; - continue; - case ESsetG1: - if (c == '0') - G1_charset = GRAF_MAP; - else if (c == 'B') - G1_charset = LAT1_MAP; - else if (c == 'U') - G1_charset = IBMPC_MAP; - else if (c == 'K') - G1_charset = USER_MAP; - if (charset == 1) - translate = set_translate(G1_charset); - vc_state = ESnormal; - continue; - default: - vc_state = ESnormal; - } - } - enable_bh(CONSOLE_BH); - return n; -} - -static int con_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int retval; - - retval = do_con_write(tty, from_user, buf, count); - con_flush_chars(tty); - - return retval; -} - -static void con_put_char(struct tty_struct *tty, unsigned char ch) -{ - do_con_write(tty, 0, &ch, 1); -} - -static int con_write_room(struct tty_struct *tty) -{ - if (tty->stopped) - return 0; - return 4096; /* No limit, really; we're not buffering */ -} - -static int con_chars_in_buffer(struct tty_struct *tty) -{ - return 0; /* we're not buffering */ -} - -void poke_blanked_console(void) -{ - timer_active &= ~(1<vc_mode == KD_GRAPHICS) - return; - if (console_blanked) { - timer_table[BLANK_TIMER].fn = unblank_screen; - timer_table[BLANK_TIMER].expires = 0; - timer_active |= 1< 0) { - c = *(b++); - if (c == 10 || c == 13 || c == 8 || need_wrap) { - if ((cnt = b - start - 1) > 0) { - sw->con_putcs(vc_cons[currcons].d, - start, cnt, y, x); - x += cnt; - if (need_wrap) - x--; - } - - if (c == 8) { /* backspace */ - bs(currcons); - start = b; - myx = x; - continue; - } - if (c != 13) - lf(currcons); - cr(currcons); - - if (c == 10 || c == 13) { - start = b; myx = x; continue; - } - - start = b-1; myx = x; - } - - *pos = c | (attr << 8); - if (myx == cols - 1) { - need_wrap = 1; - continue; - } - pos++; - myx++; - } - - if ((cnt = b - start) > 0) { - sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x); - x += cnt; - if (x == cols){ - x--; - need_wrap = 1; - } - } - - set_cursor(currcons); - poke_blanked_console(); - printing = 0; -} - -static int vt_console_device(void) -{ - return MKDEV(TTY_MAJOR, fg_console + 1); -} - -extern void keyboard_wait_for_keypress(void); - -struct console vt_console_driver = { - vt_console_print, do_unblank_screen, - keyboard_wait_for_keypress, vt_console_device -}; -#endif - -/* - * con_throttle and con_unthrottle are only used for - * paste_selection(), which has to stuff in a large number of - * characters... - */ -static void con_throttle(struct tty_struct *tty) -{ -} - -static void con_unthrottle(struct tty_struct *tty) -{ - struct vt_struct *vt = (struct vt_struct *) tty->driver_data; - - wake_up_interruptible(&vt->paste_wait); -} - -static void vc_init(unsigned int currcons, int do_clear) -{ - long base = (long) vc_scrbuf[currcons]; - - pos = (unsigned short *)(origin = (ulong)video_mem_start = base); - scr_end = base + screenbuf_size; - video_mem_end = base + screenbuf_size; - reset_vc(currcons); - def_color = 0x07; /* white */ - ulcolor = 0x0f; /* bold white */ - halfcolor = 0x08; /* grey */ - vt_cons[currcons]->paste_wait = 0; - reset_terminal(currcons, do_clear); -} - -/* - * This is the console switching bottom half handler. - * - * Doing console switching in a bottom half handler allows - * us to do the switches asynchronously (needed when we want - * to switch due to a keyboard interrupt), while still giving - * us the option to easily disable it to avoid races when we - * need to write to the console. - */ -static void console_bh(void) -{ - if (want_console >= 0) { - if (want_console != fg_console) { - change_console(want_console); - /* we only changed when the console had already - been allocated - a new console is not created - in an interrupt routine */ - } - want_console = -1; - } - if (do_poke_blanked_console) { /* do not unblank for a LED change */ - do_poke_blanked_console = 0; - poke_blanked_console(); - } -} - -/* - * unsigned long con_init(unsigned long); - * - * This routine initializes console interrupts, and does nothing - * else. If you want the screen to clear, call tty_write with - * the appropriate escape-sequence. - * - * Reads the information preserved by setup.s to determine the current display - * type and sets everything accordingly. - */ -__initfunc(unsigned long con_init(unsigned long kmem_start)) -{ - const char *display_desc = "????"; - unsigned int currcons = 0; - extern int serial_debug; - - memset(&console_driver, 0, sizeof(struct tty_driver)); - console_driver.magic = TTY_DRIVER_MAGIC; - console_driver.name = "tty"; - console_driver.name_base = 1; - console_driver.major = TTY_MAJOR; - console_driver.minor_start = 1; - console_driver.num = MAX_NR_CONSOLES; - console_driver.type = TTY_DRIVER_TYPE_CONSOLE; - console_driver.init_termios = tty_std_termios; - console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - console_driver.refcount = &console_refcount; - console_driver.table = console_table; - console_driver.termios = console_termios; - console_driver.termios_locked = console_termios_locked; - - console_driver.open = con_open; - console_driver.write = con_write; - console_driver.write_room = con_write_room; - console_driver.put_char = con_put_char; - console_driver.flush_chars = con_flush_chars; - console_driver.chars_in_buffer = con_chars_in_buffer; - console_driver.ioctl = vt_ioctl; - console_driver.stop = con_stop; - console_driver.start = con_start; - console_driver.throttle = con_throttle; - console_driver.unthrottle = con_unthrottle; - - if (tty_register_driver(&console_driver)) - panic("Couldn't register console driver\n"); - - kmem_start = conswitchp->con_startup (kmem_start, &display_desc); - - timer_table[BLANK_TIMER].fn = blank_screen; - timer_table[BLANK_TIMER].expires = 0; - if (blankinterval) { - timer_table[BLANK_TIMER].expires = jiffies + blankinterval; - timer_active |= 1<con_init determines console size */ - sw = conswitchp; - cons_num = currcons; - sw->con_init (vc_cons[currcons].d); - size_row = cols<<1; - screenbuf_size = rows*size_row; - - vc_scrbuf[currcons] = (unsigned short *) kmem_start; - kmem_start += screenbuf_size; - kmalloced = 0; - vc_init(currcons, currcons); - } - - currcons = fg_console = 0; - - gotoxy(currcons,0,0); - csi_J(currcons, 0); - printable = 1; - update_screen(fg_console); - sw->con_cursor(vc_cons[currcons].d, CM_DRAW); - printable = 1; - - /* If "serdebug" cmd line option was present, don't register for printk */ -#ifdef CONFIG_VT_CONSOLE - if (!serial_debug) - register_console(&vt_console_driver); - printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n", - can_do_color ? "colour":"mono", - display_desc, - cols,rows, - MIN_NR_CONSOLES, (MIN_NR_CONSOLES == 1) ? "" : "s", MAX_NR_CONSOLES); -#endif - init_bh(CONSOLE_BH, console_bh); - return kmem_start; -} - -void vesa_powerdown_screen(void) -{ - int currcons = fg_console; - - timer_active &= ~(1<con_blank(2); - break; - case 1: - case 2: - sw->con_blank(4); - break; - } -} - -void do_blank_screen(int nopowersave) -{ - int currcons; - - if (console_blanked) - return; - - if (!vc_cons_allocated(fg_console)) { - /* impossible */ - printk("blank_screen: tty %d not allocated ??\n", fg_console+1); - return; - } - - /* don't blank graphics */ - if (vt_cons[fg_console]->vc_mode == KD_TEXT) { - if (vesa_off_interval && !nopowersave) { - timer_table[BLANK_TIMER].fn = vesa_powerdown_screen; - timer_table[BLANK_TIMER].expires = jiffies + vesa_off_interval; - timer_active |= (1<con_blank(1); - if (!nopowersave) - sw->con_blank(vesa_blank_mode + 1); - } - else - hide_cursor(fg_console); - console_blanked = fg_console + 1; -} - -void do_unblank_screen(void) -{ - int currcons; - - if (!console_blanked) - return; - if (!vc_cons_allocated(fg_console)) { - /* impossible */ - printk("unblank_screen: tty %d not allocated ??\n", fg_console+1); - return; - } - timer_table[BLANK_TIMER].fn = blank_screen; - if (blankinterval) { - timer_table[BLANK_TIMER].expires = jiffies + blankinterval; - timer_active |= 1<con_blank (0)) - /* Low-level driver cannot restore -> do it ourselves */ - update_screen( fg_console ); - set_cursor (fg_console); -} - -void update_screen(int new_console) -{ - int currcons = fg_console; - int xx, yy, startx, attr_save; - char buf[256], *bufp; - unsigned short *p; - static int lock = 0; - - if (/* new_console == fg_console || */ lock) - return; - if (!vc_cons_allocated(new_console)) { - /* strange ... */ - printk("update_screen: tty %d not allocated ??\n", new_console+1); - return; - } - lock = 1; - - clear_selection(); - - currcons = fg_console = new_console; - sw->con_cursor (vc_cons[currcons].d, CM_ERASE); - sw->con_switch (vc_cons[new_console].d); - /* Update the screen contents */ - p = video_mem_start; - attr_save = attr; - for (yy = 0; yy < rows; yy++) - { - bufp = buf; - for (startx = xx = 0; xx < cols; xx++) - { - if (attr != ((*p >> 8) & 0xff)) - { - if (bufp > buf) - sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, - yy, startx); - startx = xx; - bufp = buf; - attr = (*p >> 8) & 0xff; - } - *bufp++ = *p++; - if (bufp == buf + sizeof (buf)) - { - sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, - yy, startx); - startx = xx + 1; - bufp = buf; - } - } - if (bufp > buf) - sw->con_putcs (vc_cons[currcons].d, buf, bufp - buf, - yy, startx); - } - set_cursor (currcons); - attr = attr_save; - set_leds(); - compute_shiftstate(); - lock = 0; -} - -/* - * If a blank_screen is due to a timer, then a power save is allowed. - * If it is related to console_switching, then avoid vesa_blank(). - */ -static void blank_screen(void) -{ - do_blank_screen(0); -} - -static void unblank_screen(void) -{ - do_unblank_screen(); -} - -/* - * Allocate the console screen memory. - */ -static int con_open(struct tty_struct *tty, struct file * filp) -{ - unsigned int currcons; - int i; - - currcons = MINOR(tty->device) - tty->driver.minor_start; - - i = vc_allocate(currcons); - if (i) - return i; - - vt_cons[currcons]->vc_num = currcons; - tty->driver_data = vt_cons[currcons]; - - if (!tty->winsize.ws_row && !tty->winsize.ws_col) { - tty->winsize.ws_row = rows; - tty->winsize.ws_col = cols; - } - - return 0; -} - -/* - * PIO_FONT support. - * - * Currently we only support 8 pixels wide fonts, at a maximum height - * of 32 pixels. Userspace fontdata is stored with 32 bytes reserved - * for each character which is kinda wasty, but this is done in order - * to maintain compatibility with the EGA/VGA fonts. It is upto the - * actual low-level console-driver convert data into its favorite - * format (maybe we should add a `fontoffset' field to the `display' - * structure so we wont have to convert the fontdata all the time. - * /Jes - */ - -#define cmapsz 8192 - -static int set_get_font(char * arg, int set, int ch512) -{ -#ifdef CAN_LOAD_EGA_FONTS - int i, unit, size; - char *charmap; - - if (!arg) - return -EINVAL; - - - size = ch512 ? 2*cmapsz : cmapsz; - - charmap = (char *)kmalloc(size, GFP_USER); - - if (set){ - if (copy_from_user(charmap, arg, size)) { - kfree(charmap); - return -EFAULT; - } - - for (unit = 32; unit > 0; unit--) - for (i = 0; i < (ch512 ? 512 : 256); i++) - if (charmap[32*i+unit-1]) - goto nonzero; - nonzero: - i = conswitchp->con_set_font(vc_cons[fg_console].d, 8, - unit, charmap); - }else{ - memset(charmap, 0, size); - i = conswitchp->con_get_font(vc_cons[fg_console].d, - &unit, &unit, charmap); - if (i == 0 && copy_to_user(arg, charmap, size)) - i = -EFAULT; - } - kfree(charmap); - - return i; -#else - return -EINVAL; -#endif -} - -/* - * Load palette into the EGA/VGA DAC registers. arg points to a colour - * map, 3 bytes per colour, 16 colours, range from 0 to 255. - */ - -static int set_get_cmap(unsigned char *arg, int set) -{ - int i, j, k; - - for (i = 0; i < 16; i++) - if (set) { - get_user(default_red[i], arg++); - get_user(default_grn[i], arg++); - get_user(default_blu[i], arg++); - } else { - put_user(default_red[i], arg++); - put_user(default_grn[i], arg++); - put_user(default_blu[i], arg++); - } - if (set) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) - for (j = k = 0; j < 16; j++) { - vc_cons[i].d->vc_palette[k++] = - default_red[j]; - vc_cons[i].d->vc_palette[k++] = - default_grn[j]; - vc_cons[i].d->vc_palette[k++] = - default_blu[j]; - } - set_palette(); - } - return 0; -} - -int con_set_cmap (unsigned char *arg) -{ - return set_get_cmap (arg, 1); -} - -int con_get_cmap (unsigned char *arg) -{ - return set_get_cmap (arg, 0); -} - -void reset_palette(int currcons) -{ - int j, k; - for (j = k = 0; j < 16; j++) { - palette[k++] = default_red[j]; - palette[k++] = default_grn[j]; - palette[k++] = default_blu[j]; - } - set_palette() ; -} - -void set_palette(void) -{ - if (vt_cons[fg_console]->vc_mode != KD_GRAPHICS) - conswitchp->con_set_palette(vc_cons[fg_console].d, color_table); -} - -/* - * Load font into the EGA/VGA character generator. arg points to a 8192 - * byte map, 32 bytes per character. Only first H of them are used for - * 8xH fonts (0 < H <= 32). - */ - -int con_set_font (char *arg, int ch512) -{ - int i; - - i = set_get_font (arg,1,ch512); - if ( !i ) { - hashtable_contents_valid = 0; - video_mode_512ch = ch512; - console_charmask = ch512 ? 0x1ff : 0x0ff; - } - return i; -} - -int con_get_font (char *arg) -{ - return set_get_font (arg,0,video_mode_512ch); -} - -/* - * Adjust the screen to fit a font of a certain height - * - * Returns < 0 for error, 0 if nothing changed, and the number - * of lines on the adjusted console if changed. - */ -int con_adjust_height(unsigned long fontheight) -{ - return -EINVAL; -} - -static void set_vesa_blanking(unsigned long arg) -{ - char *argp = (char *)arg + 1; - unsigned int mode; - get_user(mode, argp); - vesa_blank_mode = (mode < 4) ? mode : 0; -} - -unsigned long get_video_num_lines(unsigned int currcons) -{ - return(rows); -} - -unsigned long get_video_num_columns(unsigned int currcons) -{ - return(cols); -} - -unsigned long get_video_size_row(unsigned int currcons) -{ - return(size_row); -} 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 Mon Dec 1 20:15:39 1997 +++ new/linux/arch/m68k/kernel/entry.S Fri Feb 13 01:30:12 1998 @@ -37,6 +37,8 @@ #include #include +#include "m68k_defs.h" + .globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap) .globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception) .globl SYMBOL_NAME(ret_from_signal) @@ -63,9 +65,7 @@ ENTRY(reschedule) | save top of frame - pea %sp@ - jbsr SYMBOL_NAME(set_esp0) - addql #4,%sp + movel %sp,%curptr@(TS_ESP0) pea SYMBOL_NAME(ret_from_exception) jmp SYMBOL_NAME(schedule) @@ -98,9 +98,7 @@ GET_CURRENT(%d0) | save top of frame - pea %sp@ - jbsr SYMBOL_NAME(set_esp0) - addql #4,%sp + movel %sp,%curptr@(TS_ESP0) cmpl #NR_syscalls,%d2 jcc badsys @@ -112,6 +110,10 @@ SYMBOL_NAME_LABEL(ret_from_exception) btst #5,%sp@(LPT_OFF_SR) | check if returning to kernel bnes 2f | if so, skip resched, signals + | only allow interrupts when we are really the last one on the + | kernel stack, otherwise stack overflow can occur during + | heavy interupt load + andw #ALLOWINT,%sr tstl SYMBOL_NAME(need_resched) jne SYMBOL_NAME(reschedule) cmpl #SYMBOL_NAME(task),%curptr | task[0] cannot have signals @@ -122,16 +124,8 @@ 5: tstl %curptr@(LTASK_STATE) | state jne SYMBOL_NAME(reschedule) - tstl %curptr@(LTASK_COUNTER) | counter - jeq SYMBOL_NAME(reschedule) - movel %curptr@(LTASK_BLOCKED),%d0 - movel %d0,%d1 | save blocked in d1 for sig handling - notl %d0 - btst #LPF_PTRACED_BIT,%curptr@(LTASK_FLAGS+LPF_PTRACED_OFF) - jeq 1f - moveq #-1,%d0 | let the debugger see all signals -1: andl %curptr@(LTASK_SIGNAL),%d0 + tstl %curptr@(LTASK_SIGPENDING) jne Lsignal_return 2: RESTORE_ALL @@ -139,7 +133,7 @@ subql #4,%sp | dummy return address SAVE_SWITCH_STACK pea %sp@(SWITCH_STACK_SIZE) - movel %d1,%sp@- + clrl %sp@- bsrl SYMBOL_NAME(do_signal) addql #8,%sp RESTORE_SWITCH_STACK @@ -184,11 +178,6 @@ #endif jhi 2b #endif - /* Let the rest run with interrupts allowed. This is safe since - the kernel never uses a non-standard ipl and this is the outer - level interrupt. */ - andw #ALLOWINT,%sr - /* check if we need to do software interrupts */ movel SYMBOL_NAME(bh_active),%d0 @@ -229,12 +218,26 @@ RESTORE_SWITCH_STACK rts +ENTRY(sys_rt_sigsuspend) + SAVE_SWITCH_STACK + pea %sp@(SWITCH_STACK_SIZE) + jbsr SYMBOL_NAME(do_rt_sigsuspend) + addql #4,%sp + RESTORE_SWITCH_STACK + rts + ENTRY(sys_sigreturn) SAVE_SWITCH_STACK jbsr SYMBOL_NAME(do_sigreturn) RESTORE_SWITCH_STACK rts +ENTRY(sys_rt_sigreturn) + SAVE_SWITCH_STACK + jbsr SYMBOL_NAME(do_rt_sigreturn) + RESTORE_SWITCH_STACK + rts + SYMBOL_NAME_LABEL(resume) /* * Beware - when entering resume, offset of tss is in d1, @@ -251,11 +254,6 @@ /* save sr */ movew %sr,%a0@(LTSS_SR) -#if 0 - /* disable interrupts */ - oriw #0x0700,%sr -#endif - /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ movec %sfc,%d0 movew %d0,%a0@(LTSS_FS) @@ -415,7 +413,7 @@ .long SYMBOL_NAME(sys_mknod) .long SYMBOL_NAME(sys_chmod) /* 15 */ .long SYMBOL_NAME(sys_chown) - .long SYMBOL_NAME(sys_break) + .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */ .long SYMBOL_NAME(sys_stat) .long SYMBOL_NAME(sys_lseek) .long SYMBOL_NAME(sys_getpid) /* 20 */ @@ -429,11 +427,11 @@ .long SYMBOL_NAME(sys_fstat) .long SYMBOL_NAME(sys_pause) .long SYMBOL_NAME(sys_utime) /* 30 */ - .long SYMBOL_NAME(sys_stty) - .long SYMBOL_NAME(sys_gtty) + .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */ .long SYMBOL_NAME(sys_access) .long SYMBOL_NAME(sys_nice) - .long SYMBOL_NAME(sys_ftime) /* 35 */ + .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */ .long SYMBOL_NAME(sys_sync) .long SYMBOL_NAME(sys_kill) .long SYMBOL_NAME(sys_rename) @@ -442,7 +440,7 @@ .long SYMBOL_NAME(sys_dup) .long SYMBOL_NAME(sys_pipe) .long SYMBOL_NAME(sys_times) - .long SYMBOL_NAME(sys_prof) + .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */ .long SYMBOL_NAME(sys_brk) /* 45 */ .long SYMBOL_NAME(sys_setgid) .long SYMBOL_NAME(sys_getgid) @@ -450,14 +448,14 @@ .long SYMBOL_NAME(sys_geteuid) .long SYMBOL_NAME(sys_getegid) /* 50 */ .long SYMBOL_NAME(sys_acct) - .long SYMBOL_NAME(sys_phys) - .long SYMBOL_NAME(sys_lock) + .long SYMBOL_NAME(sys_ni_syscall) /* old phys syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */ .long SYMBOL_NAME(sys_ioctl) .long SYMBOL_NAME(sys_fcntl) /* 55 */ - .long SYMBOL_NAME(sys_mpx) + .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */ .long SYMBOL_NAME(sys_setpgid) - .long SYMBOL_NAME(sys_ulimit) - .long SYMBOL_NAME(sys_olduname) + .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */ + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_umask) /* 60 */ .long SYMBOL_NAME(sys_chroot) .long SYMBOL_NAME(sys_ustat) @@ -496,7 +494,7 @@ .long SYMBOL_NAME(sys_fchown) /* 95 */ .long SYMBOL_NAME(sys_getpriority) .long SYMBOL_NAME(sys_setpriority) - .long SYMBOL_NAME(sys_profil) + .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ .long SYMBOL_NAME(sys_statfs) .long SYMBOL_NAME(sys_fstatfs) /* 100 */ .long SYMBOL_NAME(sys_ioperm) @@ -507,7 +505,7 @@ .long SYMBOL_NAME(sys_newstat) .long SYMBOL_NAME(sys_newlstat) .long SYMBOL_NAME(sys_newfstat) - .long SYMBOL_NAME(sys_uname) + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_ni_syscall) /* iopl for i386 */ /* 110 */ .long SYMBOL_NAME(sys_vhangup) .long SYMBOL_NAME(sys_idle) @@ -568,9 +566,19 @@ .long SYMBOL_NAME(sys_query_module) .long SYMBOL_NAME(sys_poll) .long SYMBOL_NAME(sys_nfsservctl) + .long SYMBOL_NAME(sys_setresgid) /* 170 */ + .long SYMBOL_NAME(sys_getresgid) .long SYMBOL_NAME(sys_prctl) - .long SYMBOL_NAME(sys_pread) + .long SYMBOL_NAME(sys_rt_sigreturn) + .long SYMBOL_NAME(sys_rt_sigaction) + .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */ + .long SYMBOL_NAME(sys_rt_sigpending) + .long SYMBOL_NAME(sys_rt_sigtimedwait) + .long SYMBOL_NAME(sys_rt_sigqueueinfo) + .long SYMBOL_NAME(sys_rt_sigsuspend) + .long SYMBOL_NAME(sys_pread) /* 180 */ .long SYMBOL_NAME(sys_pwrite) + .long SYMBOL_NAME(sys_lchown); .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4 .long SYMBOL_NAME(sys_ni_syscall) .endr 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 Thu Jul 31 22:09:16 1997 +++ new/linux/arch/m68k/kernel/head.S Fri Feb 13 01:30:12 1998 @@ -14,6 +14,7 @@ ** 94/11/14 Andreas Schwab: put kernel at PAGESIZE ** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari ** ++ Bjoern & Roman: ATARI-68040 support for the Medusa +** 95/11/18 Richard Hirst: Added MVME166 support ** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with ** Magnum- and FX-alternate ram ** @@ -72,8 +73,7 @@ #include .globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt) -.globl SYMBOL_NAME(availmem), SYMBOL_NAME(is_medusa) -.globl SYMBOL_NAME(is_hades) +.globl SYMBOL_NAME(availmem), SYMBOL_NAME(mvme_bdid_ptr) .globl SYMBOL_NAME(m68k_pgtable_cachemode) .globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir) @@ -145,6 +145,7 @@ #define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab #define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab +#define is_not_mvme16x(lab) moveq &MACH_MVME16x,%d7; cmpl %d4,%d7; jne lab #define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab #define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab @@ -162,6 +163,7 @@ .long BOOTINFOV_MAGIC .long MACH_AMIGA, AMIGA_BOOTI_VERSION .long MACH_ATARI, ATARI_BOOTI_VERSION + .long MACH_MVME16x, MVME16x_BOOTI_VERSION .long 0 1: jra SYMBOL_NAME(_start) @@ -249,33 +251,25 @@ #ifdef CONFIG_ATARI is_not_atari(Lnotypetest) - moveq #0,%d3 /* base addr for others: 0x00000000 */ - moveq #0,%d2 /* no Hades */ - movec %d3,%vbr - lea %pc@(Ltest_berr),%a0 - movel %a0,0x8 - movel %sp,%a0 - moveb 0x0,%d1 - clrb 0x0 - nop - moveb %d1,0x0 - nop - tstb 0x00ff82fe - nop - movel #0xff000000,%d3 /* Medusa base addr: 0xff000000 */ - tstb 0xb0000000 - nop - movel #0xff000000,%d2 /* Computer is a Hades */ - moveq #0,%d3 -Ltest_berr: - movel %a0,%sp - lea %pc@(SYMBOL_NAME(is_hades)),%a0 - movel %d2,%a0@ - lea %pc@(SYMBOL_NAME(is_medusa)),%a0 - movel %d3,%a0@ - lea %pc@(Liobase),%a0 - movel %d2,%a0@ /* On a Hades the iobase must be set - before opening the serial port. */ + /* get special machine type (Medusa/Hades/AB40) */ + moveq #0,%d3 /* default if tag doesn't exist */ + movew #BI_ATARI_MCH_TYPE,%d0 + jbsr Lget_bi_record + tstl %d0 + jbmi 1f + movel %a0@,%d3 +1: + /* %d3 is not clobbered until Atari page tables are set up, + * where it is used again. */ + + /* On the Hades, the iobase must be set up before opening the + * serial port. There are no I/O regs at 0x00ffxxxx at all. */ + moveq #0,%d0 + cmpl #ATARI_MACH_HADES,%d3 + jbne 1f + movel #0xff000000,%d0 /* Hades I/O base addr: 0xff000000 */ +1: lea %pc@(Liobase),%a0 + movel %d0,%a0@ Lnotypetest: #endif @@ -543,10 +537,15 @@ area. */ - movel %pc@(is_medusa),%d3 - bne 1f - movel %pc@(is_hades),%d3 -1: + /* I/O base addr for non-Medusa, non-Hades: 0x00000000 */ + moveq #0,%d0 + cmpl #ATARI_MACH_MEDUSA,%d3 + jbeq 2f + cmpl #ATARI_MACH_HADES,%d3 + jbne 1f +2: movel #0xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */ +1: movel %d0,%d3 + /* Let the root table point to the new pointer table */ lea %a4@(PTR_TABLE_SIZE<<2),%a4 movel %a4,%a0 @@ -616,6 +615,30 @@ Lnotatari: #endif +#if defined(CONFIG_MVME16x) + is_not_mvme16x(Lnot16x) + + /* Get pointer to board ID data */ + movel %d2,%sp@- + .long 0x4e4f0070 /* trap 0x70 - .BRD_ID */ + movel %sp@+,%d2 + lea %pc@(SYMBOL_NAME(mvme_bdid_ptr)),%a0 + movel %d2,%a0@ + + /* + * On MVME16x 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. + */ + + movel #0xe01f0000,%d2 /* logical address base */ + orw #0xa040,%d2 /* add in magic bits */ + .long 0x4e7b2005 /* movec d2,ittr1 */ + .long 0x4e7b2007 /* movec d2,dttr1 */ + +Lnot16x: +#endif + /* * Setup a transparent mapping of the physical memory we are executing in. * @@ -810,6 +833,26 @@ Lmapphysnotatari: #endif +#if defined(CONFIG_MVME16x) + is_not_mvme16x(Lmapphysnot16x) + /* + * save physaddr of phys mem in register a3 + */ + moveq #'L',%d7 + jbsr Lserial_putc + + .word 0xf4d8 /* CINVA I/D */ + .word 0xf518 /* pflusha */ + .long 0x4e7bd807 /* movec a5,srp */ + .long 0x4e7bd806 /* movec a5,urp */ + movel #(TC_ENABLE+TC_PAGE4K),%d0 + .long 0x4e7b0003 /* movec d0,tc (enable the MMU) */ + jra LdoneMMUenable /* branch to continuation of startup */ + +Lmapphysnot16x: + +#endif + LdoneMMUenable: /* @@ -833,30 +876,6 @@ putc('N') -#if 0 - putr() - lea SYMBOL_NAME(kernel_pmd_table),%a0 - moveq #63,%d0 -1: moveq #7,%d1 - putn(%a0) - putc(':') - putc(' ') -2: putn(%a0@+) - dbra %d1,2b - putr() - dbra %d0,1b - putr() - movel SYMBOL_NAME(kpt),%a0 - moveq #639,%d0 -1: moveq #7,%d1 - putn(%a0) - putc(':') - putc(' ') -2: putn(%a0@+) - dbra %d1,2b - putr() - dbra %d0,1b -#endif /* * Enable caches */ @@ -899,6 +918,7 @@ /* jump to the kernel start */ putr() + subl %a6,%a6 /* clear a6 for gdb */ jbsr SYMBOL_NAME(start_kernel) /* @@ -1048,6 +1068,13 @@ */ Lserial_putc: moveml %a0/%a1,%sp@- +#if defined(CONFIG_MVME16x) + cmpil #MACH_MVME16x,%d4 + jne 2f + moveb %d7,%sp@- + .long 0x4e4f0020 +2: +#endif #ifdef CONFIG_AMIGA cmpil #MACH_AMIGA,%d4 jne 2f @@ -1130,6 +1157,7 @@ moveml %sp@+,%d0-%d2/%d7 rts +#if 0 Lshowtest: moveml %a0/%d7,%sp@- putc('A') @@ -1158,7 +1186,7 @@ putr() moveml %sp@+,%a0/%d7 rts - +#endif .data .even Lcustom: @@ -1169,9 +1197,7 @@ .long 0 SYMBOL_NAME_LABEL(availmem) .long 0 -SYMBOL_NAME_LABEL(is_medusa) - .long 0 -SYMBOL_NAME_LABEL(is_hades) - .long 0 SYMBOL_NAME_LABEL(m68k_pgtable_cachemode) + .long 0 +SYMBOL_NAME_LABEL(mvme_bdid_ptr) .long 0 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 Wed May 14 07:41:02 1997 +++ new/linux/arch/m68k/kernel/ints.c Fri Feb 13 01:30:12 1998 @@ -53,7 +53,7 @@ unsigned int local_irq_count[NR_CPUS]; -int __m68k_bh_counter; +unsigned int local_bh_count[NR_CPUS]; static void dummy_enable_irq(unsigned int irq); static void dummy_disable_irq(unsigned int irq); @@ -214,7 +214,7 @@ { if (vec >= VEC_INT1 && vec <= VEC_INT7) { vec -= VEC_SPUR; - kstat.interrupts[vec]++; + kstat.irqs[0][vec]++; irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); } else { if (mach_process_int) @@ -233,7 +233,7 @@ if (mach_default_handler) { for (i = 0; i < SYS_IRQS; i++) { len += sprintf(buf+len, "auto %2d: %10u ", i, - i ? kstat.interrupts[i] : num_spurious); + i ? kstat.irqs[0][i] : num_spurious); if (irq_list[i].flags & IRQ_FLG_LOCK) len += sprintf(buf+len, "L "); else diff -ur --new-file old/linux/arch/m68k/kernel/m68k_defs.c new/linux/arch/m68k/kernel/m68k_defs.c --- old/linux/arch/m68k/kernel/m68k_defs.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/kernel/m68k_defs.c Fri Feb 13 01:30:12 1998 @@ -0,0 +1,23 @@ +/* + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + */ + +#include +#include + +#define DEFINE(sym, val) \ + asm volatile("\n#define " #sym " %0" : : "i" (val)) + +int main(void) +{ + DEFINE(TS_TSS, offsetof(struct task_struct, tss)); + DEFINE(TS_ESP0, offsetof(struct task_struct, tss.esp0)); + DEFINE(TS_FPU, offsetof(struct task_struct, tss.fp)); + return 0; +} 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 Wed May 14 07:41:02 1997 +++ new/linux/arch/m68k/kernel/m68k_ksyms.c Wed Mar 18 06:15:40 1998 @@ -1,4 +1,3 @@ -#include #include #include #include @@ -8,6 +7,7 @@ #include #include #include +#include #include #include @@ -26,16 +26,15 @@ /* platform dependent support */ -EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL(m68k_machtype); EXPORT_SYMBOL(m68k_cputype); EXPORT_SYMBOL(m68k_is040or060); EXPORT_SYMBOL(cache_push); -EXPORT_SYMBOL(cache_push_v); EXPORT_SYMBOL(cache_clear); EXPORT_SYMBOL(mm_vtop); EXPORT_SYMBOL(mm_ptov); EXPORT_SYMBOL(mm_end_of_chunk); +EXPORT_SYMBOL(kernel_map); EXPORT_SYMBOL(m68k_debug_device); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_thread); @@ -43,7 +42,7 @@ EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(local_irq_count); -EXPORT_SYMBOL(__m68k_bh_counter); +EXPORT_SYMBOL(local_bh_count); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy); @@ -55,7 +54,12 @@ EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__up_wakeup); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif 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 Sat Aug 16 18:51:07 1997 +++ new/linux/arch/m68k/kernel/process.c Wed Mar 18 05:56:44 1998 @@ -40,6 +40,7 @@ */ 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; @@ -65,7 +66,7 @@ current->priority = -100; current->counter = -100; for (;;){ - if (!resched_needed()) + if (!need_resched) #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC) /* block out HSYNC on the atari (falcon) */ __asm__("stop #0x2200" : : : "cc"); @@ -113,17 +114,14 @@ printk("USP: %08lx\n", rdusp()); } -/* - * Free current thread data structures etc.. - */ -void exit_thread(void) -{ -} - void flush_thread(void) { + unsigned long zero = 0; set_fs(USER_DS); - current->tss.fs = USER_DS; + current->tss.fs = __USER_DS; + asm volatile (".chip 68k/68881\n\t" + "frestore %0@\n\t" + ".chip 68k" : : "a" (&zero)); } /* @@ -160,10 +158,6 @@ return ret; } -void release_thread(struct task_struct *dead_task) -{ -} - int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, struct task_struct * p, struct pt_regs * regs) { @@ -190,13 +184,12 @@ * Must save the current SFC/DFC value, NOT the value when * the parent was last descheduled - RGH 10-08-96 */ - p->tss.fs = get_fs(); + p->tss.fs = get_fs().seg; /* Copy the current fpu state */ asm volatile ("fsave %0" : : "m" (p->tss.fpstate[0]) : "memory"); - if((!CPU_IS_060 && p->tss.fpstate[0]) || - (CPU_IS_060 && p->tss.fpstate[2])) + if (!CPU_IS_060 ? p->tss.fpstate[0] : p->tss.fpstate[2]) asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" : : "m" (p->tss.fp[0]), "m" (p->tss.fpcntl[0]) @@ -215,7 +208,7 @@ /* First dump the fpu context to avoid protocol violation. */ asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); - if((!CPU_IS_060 && !fpustate[0]) || (CPU_IS_060 && !fpustate[2])) + if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) return 0; asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" 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 Sat Aug 16 18:51:07 1997 +++ new/linux/arch/m68k/kernel/ptrace.c Fri Feb 13 01:30:12 1998 @@ -10,7 +10,6 @@ * this archive for more details. */ -#include #include #include #include @@ -24,6 +23,7 @@ #include #include #include +#include /* * does not yet catch signals sent when the child dies. @@ -439,7 +439,7 @@ long tmp; ret = -EIO; - if ((unsigned long) data >= NSIG) + if ((unsigned long) data >= _NSIG) goto out; if (request == PTRACE_SYSCALL) child->flags |= PF_TRACESYS; @@ -477,7 +477,7 @@ long tmp; ret = -EIO; - if ((unsigned long) data >= NSIG) + if ((unsigned long) data >= _NSIG) goto out; child->flags &= ~PF_TRACESYS; tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); @@ -494,7 +494,7 @@ long tmp; ret = -EIO; - if ((unsigned long) data >= NSIG) + if ((unsigned long) data >= _NSIG) goto out; child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); @@ -509,6 +509,59 @@ goto out; } + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + tmp = get_reg(child, i); + if (i == PT_SR) + tmp >>= 16; + if (put_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + goto out; + } + data += sizeof(long); + } + ret = 0; + goto out; + } + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + if (get_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + goto out; + } + if (i == PT_SR) { + tmp &= SR_MASK; + tmp <<= 16; + tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); + } + put_reg(child, i, tmp); + data += sizeof(long); + } + ret = 0; + goto out; + } + + case PTRACE_GETFPREGS: { /* Get the child FPU state. */ + ret = 0; + if (copy_to_user((void *)data, &child->tss.fp, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + goto out; + } + + case PTRACE_SETFPREGS: { /* Set the child FPU state. */ + ret = 0; + if (copy_from_user(&child->tss.fp, (void *)data, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + goto out; + } + default: ret = -EIO; goto out; @@ -533,9 +586,10 @@ * for normal use. strace only continues with a signal if the * stopping signal is not SIGTRAP. -brl */ - if (current->exit_code) - current->signal |= (1 << (current->exit_code - 1)); - current->exit_code = 0; + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } out: unlock_kernel(); } 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 Jun 17 01:35:53 1997 +++ new/linux/arch/m68k/kernel/setup.c Fri Feb 13 01:30:12 1998 @@ -36,15 +36,13 @@ #include #endif -u_long m68k_machtype; -u_long m68k_cputype; -u_long m68k_fputype; -u_long m68k_mmutype; +unsigned long m68k_machtype; +unsigned long m68k_cputype; +unsigned long m68k_fputype; +unsigned long m68k_mmutype; int m68k_is040or060 = 0; -char m68k_debug_device[6] = ""; - extern int end; extern unsigned long availmem; @@ -56,6 +54,8 @@ static char m68k_command_line[CL_SIZE]; char saved_command_line[CL_SIZE]; +char m68k_debug_device[6] = ""; + void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata; /* machine dependent keyboard functions */ int (*mach_keyb_init) (void) __initdata; @@ -74,23 +74,34 @@ int (*mach_hwclk) (int, struct hwclk_time*) = NULL; int (*mach_set_clock_mmss) (unsigned long) = NULL; void (*mach_reset)( void ); -struct fb_info *(*mach_fb_init)(long *) __initdata; long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ -void (*mach_video_setup) (char *, int *) __initdata; -#ifdef CONFIG_BLK_DEV_FD -int (*mach_floppy_init) (void) __initdata = NULL; +#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) void (*mach_floppy_setup) (char *, int *) __initdata = NULL; void (*mach_floppy_eject) (void) = NULL; #endif +#ifdef CONFIG_HEARTBEAT +void (*mach_heartbeat) (int) = NULL; +#endif + +extern void base_trap_init(void); + +#ifdef CONFIG_MAGIC_SYSRQ +int mach_sysrq_key = -1; +int mach_sysrq_shift_state = 0; +int mach_sysrq_shift_mask = 0; +char *mach_sysrq_xlate = NULL; +#endif 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 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_mvme16x(void); #define MASK_256K 0xfffc0000 @@ -132,6 +143,8 @@ unknown = amiga_parse_bootinfo(record); else if (MACH_IS_ATARI) unknown = atari_parse_bootinfo(record); + else if (MACH_IS_MAC) + unknown = mac_parse_bootinfo(record); else unknown = 1; } @@ -145,7 +158,6 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { - unsigned long memory_start, memory_end; extern int _etext, _edata, _end; int i; char *p, *q; @@ -158,19 +170,15 @@ else if (CPU_IS_060) m68k_is040or060 = 6; + base_trap_init(); + /* clear the fpu if we have one */ if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { volatile int zero = 0; asm __volatile__ ("frestore %0" : : "m" (zero)); } - memory_start = availmem; - memory_end = 0; - - for (i = 0; i < m68k_num_memory; i++) - memory_end += m68k_memory[i].size & MASK_256K; - - init_task.mm->start_code = 0; + init_task.mm->start_code = PAGE_OFFSET; init_task.mm->end_code = (unsigned long) &_etext; init_task.mm->end_data = (unsigned long) &_edata; init_task.mm->brk = (unsigned long) &_end; @@ -190,6 +198,15 @@ if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0; i = 1; } +#ifdef CONFIG_ATARI + /* This option must be parsed very early */ + if (!strncmp( p, "switches=", 9 )) { + extern void atari_switches_setup( const char *, int ); + atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ? + (q - (p+9)) : strlen(p+9) ); + i = 1; + } +#endif if (i) { /* option processed, delete it */ @@ -202,9 +219,6 @@ } } - *memory_start_p = memory_start; - *memory_end_p = memory_end; - switch (m68k_machtype) { #ifdef CONFIG_AMIGA case MACH_AMIGA: @@ -231,6 +245,11 @@ config_apollo(); break; #endif +#ifdef CONFIG_MVME16x + case MACH_MVME16x: + config_mvme16x(); + break; +#endif default: panic ("No configuration setup"); } @@ -241,6 +260,11 @@ initrd_end = initrd_start + m68k_ramdisk.size; } #endif + + *memory_start_p = availmem; + *memory_end_p = 0; + for (i = 0; i < m68k_num_memory; i++) + *memory_end_p += m68k_memory[i].size & MASK_256K; } int get_cpuinfo(char * buffer) @@ -337,15 +361,7 @@ return(len); } -#ifdef CONFIG_BLK_DEV_FD -__initfunc(int floppy_init(void)) -{ - if (mach_floppy_init) - return mach_floppy_init(); - else - return 0; -} - +#if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) __initfunc(void floppy_setup(char *str, int *ints)) { if (mach_floppy_setup) @@ -373,8 +389,16 @@ *year = *mon = *day = *hour = *min = *sec = 0; } -__initfunc(void video_setup (char *options, int *ints)) +void check_bugs(void) { - if (mach_video_setup) - mach_video_setup (options, ints); +#ifndef CONFIG_FPU_EMU + if (m68k_fputype == 0) { + printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " + "WHICH IS REQUIRED BY LINUX/M68K ***\n" ); + printk( KERN_EMERG "Upgrade your hardware or join the FPU " + "emulation project\n" ); + printk( KERN_EMERG "(see http://no-fpu.linux-m68k.org)\n" ); + panic( "no FPU" ); + } +#endif } diff -ur --new-file old/linux/arch/m68k/kernel/signal.c new/linux/arch/m68k/kernel/signal.c --- old/linux/arch/m68k/kernel/signal.c Sat Aug 16 18:51:07 1997 +++ new/linux/arch/m68k/kernel/signal.c Fri Feb 13 01:30:12 1998 @@ -12,13 +12,15 @@ * Linux/m68k support by Hamish Macdonald * * 68060 fixes by Jesper Skov + * + * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab */ /* * ++roman (07/09/96): implemented signal stacks (specially for tosemu on * Atari :-) Current limitation: Only one sigstack can be active at one time. - * If a second signal with SA_STACK set arrives while working on a sigstack, - * SA_STACK is ignored. This behaviour avoids lots of trouble with nested + * If a second signal with SA_ONSTACK set arrives while working on a sigstack, + * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested * signal handlers! */ @@ -30,22 +32,19 @@ #include #include #include +#include #include #include #include #include +#include -#define offsetof(type, member) ((size_t)(&((type *)0)->member)) - -#define _S(nr) (1<<((nr)-1)) - -#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, int options, unsigned long *ru); - -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); const int frame_extra_sizes[16] = { 0, @@ -67,54 +66,232 @@ }; /* - * atomically swap in the new signal mask, and wait for a signal. + * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int do_sigsuspend(struct pt_regs *regs) { - unsigned long oldmask = current->blocked; - unsigned long newmask = regs->d3; + old_sigset_t mask = regs->d3; + sigset_t saveset; + + mask &= _BLOCKABLE; + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(current); + + regs->d0 = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs)) + return -EINTR; + } +} + +asmlinkage int +do_rt_sigsuspend(struct pt_regs *regs) +{ + sigset_t *unewset = (sigset_t *)regs->d1; + size_t sigsetsize = (size_t)regs->d2; + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(current); - current->blocked = newmask & _BLOCKABLE; regs->d0 = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(oldmask, regs)) + if (do_signal(&saveset, regs)) return -EINTR; } } +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + + +/* + * Do a signal return; undo the signal stack. + */ + +struct sigframe +{ + char *pretcode; + int sig; + int code; + struct sigcontext *psc; + char retcode[8]; + unsigned long extramask[_NSIG_WORDS-1]; + struct sigcontext sc; +}; + +struct rt_sigframe +{ + char *pretcode; + int sig; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + char retcode[8]; +}; + + static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ -asmlinkage int do_sigreturn(unsigned long __unused) +static inline void restore_fpu_state(struct sigcontext *sc) { - struct sigcontext context; - struct pt_regs *regs; - struct switch_stack *sw; - int fsize = 0; - int formatvec = 0; - unsigned long fp; - unsigned long usp = rdusp(); + if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { + /* Verify the frame format. */ + if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) + goto badframe; + if (CPU_IS_020_OR_030) { + if (m68k_fputype & FPU_68881 && + !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4)) + goto badframe; + if (m68k_fputype & FPU_68882 && + !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4)) + goto badframe; + } else if (CPU_IS_040) { + if (!(sc->sc_fpstate[1] == 0x00 || + sc->sc_fpstate[1] == 0x28 || + sc->sc_fpstate[1] == 0x60)) + goto badframe; + } else if (CPU_IS_060) { + if (!(sc->sc_fpstate[3] == 0x00 || + sc->sc_fpstate[3] == 0x60 || + sc->sc_fpstate[3] == 0xe0)) + goto badframe; + } else + goto badframe; -#if 0 - printk("sys_sigreturn, usp=%08x\n", (unsigned) usp); -#endif + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %0,%/fp0-%/fp1\n\t" + "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); + } + __asm__ volatile (".chip 68k/68881\n\t" + "frestore %0\n\t" + ".chip 68k" : : "m" (*sc->sc_fpstate)); + return; + +badframe: + do_exit(SIGSEGV); +} - /* get stack frame pointer */ - sw = (struct switch_stack *) &__unused; - regs = (struct pt_regs *) (sw + 1); +#define FPCONTEXT_SIZE 216 +#define uc_fpstate uc_filler[0] +#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] +#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] - /* get previous context (including pointer to possible extra junk) */ - if (copy_from_user(&context,(void *)usp, sizeof(context))) +static inline void rt_restore_fpu_state(struct ucontext *uc) +{ + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = CPU_IS_060 ? 8 : 0; + fpregset_t fpregs; + + if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) + goto badframe; + if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { + if (!CPU_IS_060) + context_size = fpstate[1]; + /* Verify the frame format. */ + if (!CPU_IS_060 && (fpstate[0] != fpu_version)) + goto badframe; + if (CPU_IS_020_OR_030) { + if (m68k_fputype & FPU_68881 && + !(context_size == 0x18 || context_size == 0xb4)) + goto badframe; + if (m68k_fputype & FPU_68882 && + !(context_size == 0x38 || context_size == 0xd4)) + goto badframe; + } else if (CPU_IS_040) { + if (!(context_size == 0x00 || + context_size == 0x28 || + context_size == 0x60)) + goto badframe; + } else if (CPU_IS_060) { + if (!(fpstate[3] == 0x00 || + fpstate[3] == 0x60 || + fpstate[3] == 0xe0)) + goto badframe; + } else + goto badframe; + if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, + sizeof(fpregs))) + goto badframe; + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %0,%/fp0-%/fp7\n\t" + "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*fpregs.f_fpregs), + "m" (fpregs.f_pcr)); + } + if (context_size && + __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1, + context_size)) goto badframe; + __asm__ volatile (".chip 68k/68881\n\t" + "frestore %0\n\t" + ".chip 68k" : : "m" (*fpstate)); + return; - fp = usp + sizeof (context); +badframe: + do_exit(SIGSEGV); +} - /* restore signal mask */ - current->blocked = context.sc_mask & _BLOCKABLE; +static inline int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp) +{ + int fsize, formatvec; + struct sigcontext context; + /* get previous context */ + if (copy_from_user(&context, usc, sizeof(context))) + goto badframe; + /* restore passed registers */ - regs->d0 = context.sc_d0; regs->d1 = context.sc_d1; regs->a0 = context.sc_a0; regs->a1 = context.sc_a1; @@ -125,43 +302,8 @@ formatvec = context.sc_formatvec; regs->format = formatvec >> 12; regs->vector = formatvec & 0xfff; - if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){ - /* Verify the frame format. */ - if (!CPU_IS_060 && (context.sc_fpstate[0] != fpu_version)) - goto badframe; - if (m68k_fputype & FPU_68881) - { - if (context.sc_fpstate[1] != 0x18 - && context.sc_fpstate[1] != 0xb4) - goto badframe; - } - else if (m68k_fputype & FPU_68882) - { - if (context.sc_fpstate[1] != 0x38 - && context.sc_fpstate[1] != 0xd4) - goto badframe; - } - else if (m68k_fputype & FPU_68040) - { - if (!(context.sc_fpstate[1] == 0x00 || - context.sc_fpstate[1] == 0x28 || - context.sc_fpstate[1] == 0x60)) - goto badframe; - } - else if (m68k_fputype & FPU_68060) - { - if (!(context.sc_fpstate[3] == 0x00 || - context.sc_fpstate[3] == 0x60 || - context.sc_fpstate[3] == 0xe0)) - goto badframe; - } - __asm__ volatile ("fmovemx %0,%/fp0-%/fp1\n\t" - "fmoveml %1,%/fpcr/%/fpsr/%/fpiar" - : /* no outputs */ - : "m" (*context.sc_fpregs), - "m" (*context.sc_fpcntl)); - } - __asm__ volatile ("frestore %0" : : "m" (*context.sc_fpstate)); + + restore_fpu_state(&context); fsize = frame_extra_sizes[regs->format]; if (fsize < 0) { @@ -174,14 +316,13 @@ goto badframe; } - if (context.sc_usp != fp+fsize) - current->flags &= ~PF_ONSIGSTK; - /* OK. Make room on the supervisor stack for the extra junk, * if necessary. */ if (fsize) { + struct switch_stack *sw = (struct switch_stack *)regs - 1; + regs->d0 = context.sc_d0; #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) __asm__ __volatile__ (" movel %0,%/a0\n\t" @@ -215,127 +356,494 @@ goto badframe; } + return context.sc_d0; + +badframe: + do_exit(SIGSEGV); +} + +static inline int +rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, + struct ucontext *uc) +{ + int fsize, temp; + greg_t *gregs = uc->uc_mcontext.gregs; + + __get_user(temp, &uc->uc_mcontext.version); + if (temp != MCONTEXT_VERSION) + goto badframe; + /* restore passed registers */ + __get_user(regs->d0, &gregs[0]); + __get_user(regs->d1, &gregs[1]); + __get_user(regs->d2, &gregs[2]); + __get_user(regs->d3, &gregs[3]); + __get_user(regs->d4, &gregs[4]); + __get_user(regs->d5, &gregs[5]); + __get_user(sw->d6, &gregs[6]); + __get_user(sw->d7, &gregs[7]); + __get_user(regs->a0, &gregs[8]); + __get_user(regs->a1, &gregs[9]); + __get_user(regs->a2, &gregs[10]); + __get_user(sw->a3, &gregs[11]); + __get_user(sw->a4, &gregs[12]); + __get_user(sw->a5, &gregs[13]); + __get_user(sw->a6, &gregs[14]); + __get_user(temp, &gregs[15]); + wrusp(temp); + __get_user(regs->pc, &gregs[16]); + __get_user(temp, &gregs[17]); + regs->sr = (regs->sr & 0xff00) | (temp & 0xff); + regs->orig_d0 = -1; /* disable syscall checks */ + __get_user(temp, &uc->uc_formatvec); + regs->format = temp >> 12; + regs->vector = temp & 0xfff; + + rt_restore_fpu_state(uc); + + fsize = frame_extra_sizes[regs->format]; + if (fsize < 0) { + /* + * user process trying to return with weird frame format + */ +#if DEBUG + printk("user process returning with weird frame format\n"); +#endif + goto badframe; + } + + /* OK. Make room on the supervisor stack for the extra junk, + * if necessary. + */ + + if (fsize) { +#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) + __asm__ __volatile__ + (" movel %0,%/a0\n\t" + " subl %1,%/a0\n\t" /* make room on stack */ + " movel %/a0,%/sp\n\t" /* set stack pointer */ + /* move switch_stack and pt_regs */ + "1: movel %0@+,%/a0@+\n\t" + " dbra %2,1b\n\t" + " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ + " lsrl #2,%1\n\t" + " subql #1,%1\n\t" + "2: movesl %4@+,%2\n\t" + "3: movel %2,%/a0@+\n\t" + " dbra %1,2b\n\t" + " bral " SYMBOL_NAME_STR(ret_from_signal) "\n" + "4:\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 2b,4b\n" + " .long 3b,4b\n" + ".previous" + : /* no outputs, it doesn't ever return */ + : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), + "n" (frame_offset), "a" (&uc->uc_extra) + : "a0"); +#undef frame_offset + /* + * If we ever get here an exception occured while + * building the above stack-frame. + */ + goto badframe; + } + return regs->d0; + badframe: do_exit(SIGSEGV); } +asmlinkage int do_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct sigframe *frame = (struct sigframe *)(usp - 24); + sigset_t set; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.sc_mask) || + (_NSIG_WORDS > 1 && + __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + current->blocked = set; + recalc_sigpending(current); + + return restore_sigcontext(regs, &frame->sc, frame + 1); + +badframe: + do_exit(SIGSEGV); +} + +asmlinkage int do_rt_sigreturn(unsigned long __unused) +{ + struct switch_stack *sw = (struct switch_stack *) &__unused; + struct pt_regs *regs = (struct pt_regs *) (sw + 1); + unsigned long usp = rdusp(); + struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); + sigset_t set; + + if (verify_area(VERIFY_READ, frame, sizeof(*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + current->blocked = set; + recalc_sigpending(current); + + return rt_restore_ucontext(regs, sw, &frame->uc); + +badframe: + do_exit(SIGSEGV); +} + /* - * Set up a signal frame... - * - * This routine is somewhat complicated by the fact that if the - * kernel may be entered by an exception other than a system call; - * e.g. a bus error or other "bad" exception. If this is the case, - * then *all* the context on the kernel stack frame must be saved. - * - * For a large number of exceptions, the stack frame format is the same - * as that which will be created when the process traps back to the kernel - * when finished executing the signal handler. In this case, nothing - * must be done. This is exception frame format "0". For exception frame - * formats "2", "9", "A" and "B", the extra information on the frame must - * be saved. This information is saved on the user stack and restored - * when the signal handler is returned. - * - * The format of the user stack when executing the signal handler is: - * - * usp -> RETADDR (points to code below) - * signum (parm #1) - * sigcode (parm #2 ; vector number) - * scp (parm #3 ; sigcontext pointer, pointer to #1 below) - * code1 (addaw #20,sp) ; pop parms and code off stack - * code2 (moveq #119,d0; trap #0) ; sigreturn syscall - * #1| oldmask - * | old usp - * | d0 (first saved reg) - * | d1 - * | a0 - * | a1 - * | sr (saved status register) - * | pc (old pc; one to return to) - * | forvec (format and vector word of old supervisor stack frame) - * | floating point context - * - * These are optionally followed by some extra stuff, depending on the - * stack frame interrupted. This is 1 longword for format "2", 3 - * longwords for format "9", 6 longwords for format "A", and 21 - * longwords for format "B". + * Set up a signal frame. */ -#define UFRAME_SIZE(fs) (sizeof(struct sigcontext)/4 + 6 + fs/4) +static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) +{ + __asm__ volatile (".chip 68k/68881\n\t" + "fsave %0\n\t" + ".chip 68k" + : : "m" (*sc->sc_fpstate) : "memory"); + + if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { + fpu_version = sc->sc_fpstate[0]; + if (CPU_IS_020_OR_030 && + regs->vector >= (VEC_FPBRUC * 4) && + regs->vector <= (VEC_FPNAN * 4)) { + /* Clear pending exception in 68882 idle frame */ + if (*(unsigned short *) sc->sc_fpstate == 0x1f38) + sc->sc_fpstate[0x38] |= 1 << 3; + } + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %/fp0-%/fp1,%0\n\t" + "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*sc->sc_fpregs), + "m" (*sc->sc_fpcntl) + : "memory"); + } +} -static inline void setup_frame (struct sigaction * sa, struct pt_regs *regs, - int signr, unsigned long oldmask) +static inline void rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) { - struct sigcontext context; - unsigned long *frame, *tframe; + unsigned char fpstate[FPCONTEXT_SIZE]; + int context_size = CPU_IS_060 ? 8 : 0; + + __asm__ volatile (".chip 68k/68881\n\t" + "fsave %0\n\t" + ".chip 68k" + : : "m" (*fpstate) : "memory"); + + __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); + if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { + fpregset_t fpregs; + if (!CPU_IS_060) + context_size = fpstate[1]; + fpu_version = fpstate[0]; + if (CPU_IS_020_OR_030 && + regs->vector >= (VEC_FPBRUC * 4) && + regs->vector <= (VEC_FPNAN * 4)) { + /* Clear pending exception in 68882 idle frame */ + if (*(unsigned short *) fpstate == 0x1f38) + fpstate[0x38] |= 1 << 3; + } + __asm__ volatile (".chip 68k/68881\n\t" + "fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" + ".chip 68k" + : /* no outputs */ + : "m" (*fpregs.f_fpregs), + "m" (fpregs.f_pcr) + : "memory"); + copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, sizeof(fpregs)); + } + if (context_size) + copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, + context_size); +} + +static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, + unsigned long mask) +{ + sc->sc_mask = mask; + sc->sc_usp = rdusp(); + sc->sc_d0 = regs->d0; + sc->sc_d1 = regs->d1; + sc->sc_a0 = regs->a0; + sc->sc_a1 = regs->a1; + sc->sc_sr = regs->sr; + sc->sc_pc = regs->pc; + sc->sc_formatvec = regs->format << 12 | regs->vector; + save_fpu_state(sc, regs); +} + +static inline void rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) +{ + struct switch_stack *sw = (struct switch_stack *)regs - 1; + greg_t *gregs = uc->uc_mcontext.gregs; + + __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); + __put_user(regs->d0, &gregs[0]); + __put_user(regs->d1, &gregs[1]); + __put_user(regs->d2, &gregs[2]); + __put_user(regs->d3, &gregs[3]); + __put_user(regs->d4, &gregs[4]); + __put_user(regs->d5, &gregs[5]); + __put_user(sw->d6, &gregs[6]); + __put_user(sw->d7, &gregs[7]); + __put_user(regs->a0, &gregs[8]); + __put_user(regs->a1, &gregs[9]); + __put_user(regs->a2, &gregs[10]); + __put_user(sw->a3, &gregs[11]); + __put_user(sw->a4, &gregs[12]); + __put_user(sw->a5, &gregs[13]); + __put_user(sw->a6, &gregs[14]); + __put_user(rdusp(), &gregs[15]); + __put_user(regs->pc, &gregs[16]); + __put_user(regs->sr, &gregs[17]); + __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec); + rt_save_fpu_state(uc, regs); +} + +static inline void push_cache (unsigned long vaddr) +{ + /* + * Using the old cache_push_v() was really a big waste. + * + * What we are trying to do is to flush 8 bytes to ram. + * Flushing 2 cache lines of 16 bytes is much cheaper than + * flushing 1 or 2 pages, as previously done in + * cache_push_v(). + * Jes + */ + if (CPU_IS_040) { + unsigned long temp; + + __asm__ __volatile__ (".chip 68040\n\t" + "nop\n\t" + "ptestr (%1)\n\t" + "movec %%mmusr,%0\n\t" + ".chip 68k" + : "=r" (temp) + : "a" (vaddr)); + + temp &= PAGE_MASK; + temp |= vaddr & ~PAGE_MASK; + + __asm__ __volatile__ (".chip 68040\n\t" + "nop\n\t" + "cpushl %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (temp)); + if (((vaddr + 8) ^ vaddr) & ~15) { + if (((vaddr + 8) ^ vaddr) & PAGE_MASK) + __asm__ __volatile__ (".chip 68040\n\t" + "nop\n\t" + "ptestr (%1)\n\t" + "movec %%mmusr,%0\n\t" + ".chip 68k" + : "=r" (temp) + : "a" (vaddr + 8)); + + temp &= PAGE_MASK; + temp |= (vaddr + 8) & ~PAGE_MASK; + + __asm__ __volatile__ (".chip 68040\n\t" + "nop\n\t" + "cpushl %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (temp)); + } + } + else if (CPU_IS_060) { + unsigned long temp; + __asm__ __volatile__ (".chip 68060\n\t" + "plpar (%0)\n\t" + ".chip 68k" + : "=a" (temp) + : "0" (vaddr)); + __asm__ __volatile__ (".chip 68060\n\t" + "cpushl %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (temp)); + if (((vaddr + 8) ^ vaddr) & ~15) { + if (((vaddr + 8) ^ vaddr) & PAGE_MASK) + __asm__ __volatile__ (".chip 68060\n\t" + "plpar (%0)\n\t" + ".chip 68k" + : "=a" (temp) + : "0" (vaddr + 8)); + __asm__ __volatile__ (".chip 68060\n\t" + "cpushl %%bc,(%0)\n\t" + ".chip 68k" + : : "a" (temp)); + } + } + else { + /* + * 68030/68020 have no writeback cache; + * still need to clear icache. + * Note that vaddr is guaranteed to be long word aligned. + */ + unsigned long temp; + asm volatile ("movec %%cacr,%0" : "=r" (temp)); + temp += 4; + asm volatile ("movec %0,%%caar\n\t" + "movec %1,%%cacr" + : : "r" (vaddr), "r" (temp)); + asm volatile ("movec %0,%%caar\n\t" + "movec %1,%%cacr" + : : "r" (vaddr + 4), "r" (temp)); + } +} + +static void setup_frame (int sig, struct k_sigaction *ka, + sigset_t *set, struct pt_regs *regs) +{ + struct sigframe *frame; int fsize = frame_extra_sizes[regs->format]; + struct sigcontext context; if (fsize < 0) { +#ifdef DEBUG printk ("setup_frame: Unknown frame format %#x\n", regs->format); - do_exit(SIGSEGV); +#endif + goto segv_and_exit; } - frame = (unsigned long *)rdusp(); - if (!(current->flags & PF_ONSIGSTK) && (sa->sa_flags & SA_STACK)) { - frame = (unsigned long *)sa->sa_restorer; + frame = (struct sigframe *)((rdusp() - sizeof(*frame) - fsize) & -8); + + if (!(current->flags & PF_ONSIGSTK) && (ka->sa.sa_flags & SA_ONSTACK)) { + frame = (struct sigframe *)(((unsigned long)ka->sa.sa_restorer + - sizeof(*frame) - fsize) & -8); current->flags |= PF_ONSIGSTK; } - frame -= UFRAME_SIZE(fsize); if (fsize) { - if (copy_to_user (frame + UFRAME_SIZE(0), regs + 1, fsize)) - do_exit(SIGSEGV); + if (copy_to_user (frame + 1, regs + 1, fsize)) + goto segv_and_exit; regs->stkadj = fsize; } -/* set up the "normal" stack seen by the signal handler */ - tframe = frame; + __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + + __put_user(regs->vector, &frame->code); + __put_user(&frame->sc, &frame->psc); + + if (_NSIG_WORDS > 1) + copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + + setup_sigcontext(&context, regs, set->sig[0]); + if (copy_to_user (&frame->sc, &context, sizeof(context))) + goto segv_and_exit; + + /* Set up to return from userspace. */ + __put_user(frame->retcode, &frame->pretcode); + /* addaw #20,sp */ + __put_user(0xdefc0014, (long *)(frame->retcode + 0)); + /* moveq #,d0; trap #0 */ + __put_user(0x70004e40 + (__NR_sigreturn << 16), + (long *)(frame->retcode + 4)); - /* return address points to code on stack */ + push_cache ((unsigned long) &frame->retcode); - if(put_user((ulong)(frame+4), tframe)) - do_exit(SIGSEGV); - tframe++; - if (current->exec_domain && current->exec_domain->signal_invmap) - __put_user(current->exec_domain->signal_invmap[signr], tframe); - else - __put_user(signr, tframe); - tframe++; + /* + * no matter what frame format we were using before, we + * will do the "RTE" using a normal 4 word frame. + */ + regs->format = 0; - __put_user(regs->vector, tframe); tframe++; - /* "scp" parameter. points to sigcontext */ - __put_user((ulong)(frame+6), tframe); tframe++; - -/* set up the return code... */ - __put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */ - __put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */ - -/* Flush caches so the instructions will be correctly executed. (MA) */ - cache_push_v ((unsigned long)frame, (int)tframe - (int)frame); - -/* setup and copy the sigcontext structure */ - context.sc_mask = oldmask; - context.sc_usp = rdusp(); - context.sc_d0 = regs->d0; - context.sc_d1 = regs->d1; - context.sc_a0 = regs->a0; - context.sc_a1 = regs->a1; - context.sc_sr = regs->sr; - context.sc_pc = regs->pc; - context.sc_formatvec = (regs->format << 12 | regs->vector); - __asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory"); - if ((!CPU_IS_060 && context.sc_fpstate[0]) || (CPU_IS_060 && context.sc_fpstate[2])){ - fpu_version = context.sc_fpstate[0]; - __asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t" - "fmoveml %/fpcr/%/fpsr/%/fpiar,%1" - : /* no outputs */ - : "m" (*context.sc_fpregs), - "m" (*context.sc_fpcntl) - : "memory"); + /* Set up registers for signal handler */ + wrusp ((unsigned long) frame); + regs->pc = (unsigned long) ka->sa.sa_handler; + + /* Prepare to skip over the extra stuff in the exception frame. */ + if (regs->stkadj) { + struct pt_regs *tregs = + (struct pt_regs *)((ulong)regs + regs->stkadj); +#if DEBUG + printk("Performing stackadjust=%04x\n", regs->stkadj); +#endif + /* This must be copied with decreasing addresses to + handle overlaps. */ + tregs->vector = regs->vector; + tregs->format = regs->format; + tregs->pc = regs->pc; + tregs->sr = regs->sr; } - if (copy_to_user (tframe, &context, sizeof(context))) - do_exit(SIGSEGV); + return; + +segv_and_exit: + do_exit(SIGSEGV); +} + +static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame; + int fsize = frame_extra_sizes[regs->format]; + + if (fsize < 0) { +#ifdef DEBUG + printk ("setup_frame: Unknown frame format %#x\n", + regs->format); +#endif + goto segv_and_exit; + } + + frame = (struct rt_sigframe *)((rdusp() - sizeof(*frame)) & -8); + + /* XXX: Check here if we need to switch stacks.. */ + + if (fsize) { + if (copy_to_user (&frame->uc.uc_extra, regs + 1, fsize)) + goto segv_and_exit; + regs->stkadj = fsize; + } + + __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + __put_user(&frame->info, &frame->pinfo); + __put_user(&frame->uc, &frame->puc); + __copy_to_user(&frame->info, info, sizeof(*info)); + + /* Clear all the bits of the ucontext we don't use. */ + clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + + rt_setup_ucontext(&frame->uc, regs); + if (copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set))) + goto segv_and_exit; + + /* Set up to return from userspace. */ + __put_user(frame->retcode, &frame->pretcode); + /* movel #,d0; trap #0 */ + __put_user(0x203c, (short *)(frame->retcode + 0)); + __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2)); + __put_user(0x4e40, (short *)(frame->retcode + 6)); + + push_cache ((unsigned long) &frame->retcode); /* * no matter what frame format we were using before, we @@ -345,7 +853,7 @@ /* Set up registers for signal handler */ wrusp ((unsigned long) frame); - regs->pc = (unsigned long) sa->sa_handler; + regs->pc = (unsigned long) ka->sa.sa_handler; /* Prepare to skip over the extra stuff in the exception frame. */ if (regs->stkadj) { @@ -361,13 +869,18 @@ tregs->pc = regs->pc; tregs->sr = regs->sr; } + return; + +segv_and_exit: + do_exit(SIGSEGV); } /* * OK, we're invoking a handler */ -static inline void handle_signal(unsigned long signr, struct sigaction *sa, - unsigned long oldmask, struct pt_regs *regs) +static void +handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *oldset, struct pt_regs *regs) { /* are we from a system call? */ if (regs->orig_d0 >= 0) { @@ -378,7 +891,7 @@ break; case -ERESTARTSYS: - if (!(sa->sa_flags & SA_RESTART)) { + if (!(ka->sa.sa_flags & SA_RESTART)) { regs->d0 = -EINTR; break; } @@ -390,12 +903,19 @@ } /* set up the stack frame */ - setup_frame(sa, regs, signr, oldmask); + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(sig, ka, info, oldset, regs); + else + setup_frame(sig, ka, oldset, regs); - if (sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - if (!(sa->sa_flags & SA_NOMASK)) - current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = NULL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); + sigaddset(¤t->blocked,sig); + recalc_sigpending(current); + } } /* @@ -407,29 +927,28 @@ * that the kernel can handle, and then we build all the user-level signal * handling stack-frames in one go after that. */ -asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs) +asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) { - unsigned long mask = ~current->blocked; - unsigned long signr; - struct sigaction * sa; + siginfo_t info; + struct k_sigaction *ka; current->tss.esp0 = (unsigned long) regs; - /* If the process is traced, all signals are passed to the debugger. */ - if (current->flags & PF_PTRACED) - mask = ~0UL; - while ((signr = current->signal & mask)) { - __asm__("bfffo %2,#0,#0,%1\n\t" - "bfclr %0,%1,#1\n\t" - "eorw #31,%1" - :"=m" (current->signal),"=d" (signr) - :"0" (current->signal), "1" (signr)); - sa = current->sig->action + signr; - signr++; + if (!oldset) + oldset = ¤t->blocked; + + for (;;) { + int signr; + + signr = dequeue_signal(¤t->blocked, &info); + + if (!signr) + break; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; + regs->sr &= ~PS_T; /* Did we come from a system call? */ if (regs->orig_d0 >= 0) { @@ -443,11 +962,12 @@ } notify_parent(current, SIGCHLD); schedule(); + + /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) { discard_frame: - /* Make sure that a faulted bus cycle - isn't restarted (only needed on the - 68030). */ + /* Make sure that a faulted bus cycle isn't + restarted (only needed on the 680[23]0). */ if (regs->format == 10 || regs->format == 11) { regs->stkadj = frame_extra_sizes[regs->format]; regs->format = 0; @@ -455,26 +975,43 @@ continue; } current->exit_code = 0; + + /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) goto discard_frame; - if (_S(signr) & current->blocked) { - current->signal |= _S(signr); - mask &= ~_S(signr); + + /* Update the siginfo structure. Is this good? */ + if (signr != info.si_signo) { + info.si_signo = signr; + info.si_errno = 0; + info.si_code = SI_USER; + info.si_pid = current->p_pptr->pid; + info.si_uid = current->p_pptr->uid; + } + + /* If the (new) signal is now blocked, requeue it. */ + if (sigismember(¤t->blocked, signr)) { + send_sig_info(signr, &info, current); continue; } - sa = current->sig->action + signr - 1; } - if (sa->sa_handler == SIG_IGN) { + + ka = ¤t->sig->action[signr-1]; + if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; - /* check for SIGCHLD: it's special */ - while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0) + /* Check for SIGCHLD: it's special. */ + while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } - if (sa->sa_handler == SIG_DFL) { + + if (ka->sa.sa_handler == SIG_DFL) { + int exit_code = signr; + if (current->pid == 1) continue; + switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; @@ -482,31 +1019,35 @@ case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; + /* FALLTHRU */ + case SIGSTOP: - if (current->flags & PF_PTRACED) - continue; current->state = TASK_STOPPED; current->exit_code = signr; - if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & - SA_NOCLDSTOP)) + if (!(current->p_pptr->sig->action[SIGCHLD-1] + .sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: - if (current->binfmt && current->binfmt->core_dump) { - if (current->binfmt->core_dump(signr, regs)) - signr |= 0x80; - } - /* fall through */ + if (current->binfmt + && current->binfmt->core_dump + && current->binfmt->core_dump(signr, regs)) + exit_code |= 0x80; + /* FALLTHRU */ + default: - current->signal |= _S(signr & 0x7f); + sigaddset(¤t->signal, signr); current->flags |= PF_SIGNALED; - do_exit(signr); + do_exit(exit_code); + /* NOTREACHED */ } } - handle_signal(signr, sa, oldmask, regs); + + /* Whee! Actually deliver the signal. */ + handle_signal(signr, ka, &info, oldset, regs); return 1; } diff -ur --new-file old/linux/arch/m68k/kernel/sys_m68k.c new/linux/arch/m68k/kernel/sys_m68k.c --- old/linux/arch/m68k/kernel/sys_m68k.c Thu Jul 31 22:09:16 1997 +++ new/linux/arch/m68k/kernel/sys_m68k.c Fri Feb 13 01:30:12 1998 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -308,6 +309,10 @@ } if (!--i && len) { + /* + * No need to page align here since it is done by + * virt_to_phys_040(). + */ addr += PAGE_SIZE; i = PAGE_SIZE / 16; /* Recompute physical address when crossing a page @@ -462,7 +467,14 @@ } if (!--i && len) { + + /* + * We just want to jump to the first cache line + * in the next page. + */ addr += PAGE_SIZE; + addr &= PAGE_MASK; + i = PAGE_SIZE / 16; /* Recompute physical address when crossing a page boundary. */ @@ -559,13 +571,13 @@ cacr |= 4; if (cache & FLUSH_CACHE_DATA) cacr |= 0x400; - len >>= 4; + len >>= 2; while (len--) { __asm__ __volatile__ ("movec %1, %%caar\n\t" "movec %0, %%cacr" : /* no outputs */ : "r" (cacr), "r" (addr)); - addr += 16; + addr += 4; } } else { /* Flush the whole cache, even if page granularity requested. */ @@ -587,4 +599,14 @@ out: unlock_kernel(); return ret; +} + +/* + * Old cruft + */ +asmlinkage int sys_pause(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; } 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 Wed May 14 07:41:02 1997 +++ new/linux/arch/m68k/kernel/time.c Sat Feb 21 03:28:21 1998 @@ -7,6 +7,7 @@ * Most of the stuff is located in the machine specific files. */ +#include /* CONFIG_HEARTBEAT */ #include #include #include @@ -66,11 +67,35 @@ */ if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 && xtime.tv_usec > 500000 - (tick >> 1) && - xtime.tv_usec < 500000 + (tick >> 1)) + xtime.tv_usec < 500000 + (tick >> 1)) { if (set_rtc_mmss(xtime.tv_sec) == 0) last_rtc_update = xtime.tv_sec; else last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } +#ifdef CONFIG_HEARTBEAT + /* use power LED as a heartbeat instead -- much more useful + for debugging -- based on the version for PReP by Cort */ + /* acts like an actual heart beat -- ie thump-thump-pause... */ + if (mach_heartbeat) { + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + mach_heartbeat( 1 ); + else if (cnt == 7 || cnt == dist+7) + mach_heartbeat( 0 ); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672< #include #include +#include #ifdef CONFIG_KGDB #include #endif @@ -64,23 +65,10 @@ __ALIGN_STR "\n" SYMBOL_NAME_STR(nmihandler) ": rte"); -__initfunc(void trap_init (void)) +__initfunc(void base_trap_init(void)) { - int i; - /* setup the exception vector table */ - __asm__ volatile ("movec %0,%/vbr" : : "r" ((void*)vectors)); - - for (i = 48; i < 64; i++) - vectors[i] = trap; - - for (i = 64; i < 256; i++) - vectors[i] = inthandler; - - /* if running on an amiga, make the NMI interrupt do nothing */ - if (MACH_IS_AMIGA) { - vectors[VEC_INT7] = nmihandler; - } + __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); if (CPU_IS_040) { /* set up FPSP entry points */ @@ -134,6 +122,23 @@ } } +__initfunc(void trap_init (void)) +{ + int i; + + for (i = 48; i < 64; i++) + if (!vectors[i]) + vectors[i] = trap; + + for (i = 64; i < 256; i++) + vectors[i] = inthandler; + + /* if running on an amiga, make the NMI interrupt do nothing */ + if (MACH_IS_AMIGA) { + vectors[VEC_INT7] = nmihandler; + } +} + void set_evector(int vecnum, void (*handler)(void)) { if (vecnum >= 0 && vecnum <= 256) @@ -202,7 +207,7 @@ return; } - if (fslw & (MMU060_DESC_ERR | MMU060_WP)) { + if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) { unsigned long errorcode; unsigned long addr = fp->un.fmt4.effaddr; errorcode = ((fslw & MMU060_WP) ? 1 : 0) | @@ -230,9 +235,9 @@ static inline unsigned long probe040 (int iswrite, int fc, unsigned long addr) { unsigned long mmusr; - unsigned long fs = get_fs(); + mm_segment_t fs = get_fs(); - set_fs (fc); + set_fs (MAKE_MM_SEG(fc)); if (iswrite) /* write */ @@ -261,7 +266,7 @@ unsigned long wbd, struct frame *fp) { - unsigned long fs = get_fs (); + mm_segment_t fs = get_fs (); unsigned long mmusr; unsigned long errorcode; @@ -277,7 +282,7 @@ /* just return if we can't perform the writeback */ return; - set_fs (wbs & WBTM_040); + set_fs (MAKE_MM_SEG(wbs & WBTM_040)); switch (wbs & WBSIZ_040) { case BA_SIZE_BYTE: put_user (wbd & 0xff, (char *)wba); @@ -833,34 +838,37 @@ asmlinkage void trap_c(struct frame *fp) { int sig; + siginfo_t info; - if ((fp->ptregs.sr & PS_S) - && ((fp->ptregs.vector) >> 2) == VEC_TRACE - && !(fp->ptregs.sr & PS_T)) { - /* traced a trapping instruction */ - unsigned char *lp = ((unsigned char *)&fp->un.fmt2) + 4; - current->flags |= PF_DTRACE; - /* clear the trace bit */ - (*(unsigned short *)lp) &= ~PS_T; - return; - } else if (fp->ptregs.sr & PS_S) { - bad_super_trap(fp); + if (fp->ptregs.sr & PS_S) { + if ((fp->ptregs.vector >> 2) == VEC_TRACE) { + /* traced a trapping instruction */ + current->flags |= PF_DTRACE; + } else + bad_super_trap(fp); return; } /* send the appropriate signal to the user program */ switch ((fp->ptregs.vector) >> 2) { case VEC_ADDRERR: + info.si_code = BUS_ADRALN; sig = SIGBUS; break; - case VEC_BUSERR: - sig = SIGSEGV; - break; case VEC_ILLEGAL: - case VEC_PRIV: case VEC_LINE10: case VEC_LINE11: + info.si_code = ILL_ILLOPC; + sig = SIGILL; + break; + case VEC_PRIV: + info.si_code = ILL_PRVOPC; + sig = SIGILL; + break; case VEC_COPROC: + info.si_code = ILL_COPROC; + sig = SIGILL; + break; case VEC_TRAP1: case VEC_TRAP2: case VEC_TRAP3: @@ -875,51 +883,76 @@ case VEC_TRAP12: case VEC_TRAP13: case VEC_TRAP14: + info.si_code = ILL_ILLTRP; sig = SIGILL; break; case VEC_FPBRUC: + case VEC_FPOE: + case VEC_FPNAN: + info.si_code = FPE_FLTINV; + sig = SIGFPE; + break; case VEC_FPIR: + info.si_code = FPE_FLTRES; + sig = SIGFPE; + break; case VEC_FPDIVZ: + info.si_code = FPE_FLTDIV; + sig = SIGFPE; + break; case VEC_FPUNDER: - case VEC_FPOE: + info.si_code = FPE_FLTUND; + sig = SIGFPE; + break; case VEC_FPOVER: - case VEC_FPNAN: - { - unsigned char fstate[FPSTATESIZE]; - - __asm__ __volatile__ (".chip 68k/68881\n\t" - "fsave %0@\n\t" - ".chip 68k" : : "a" (fstate) : "memory"); - /* Set the exception pending bit in the 68882 idle frame */ - if (*(unsigned short *) fstate == 0x1f38) - { - fstate[fstate[1]] |= 1 << 3; - __asm__ __volatile__ (".chip 68k/68881\n\t" - "frestore %0@\n\t" - ".chip 68k" : : "a" (fstate)); - } - } - /* fall through */ + info.si_code = FPE_FLTOVF; + sig = SIGFPE; + break; case VEC_ZERODIV: + info.si_code = FPE_INTDIV; + sig = SIGFPE; + break; + case VEC_CHK: case VEC_TRAP: + info.si_code = FPE_INTOVF; sig = SIGFPE; break; case VEC_TRACE: /* ptrace single step */ - fp->ptregs.sr &= ~PS_T; + info.si_code = TRAP_TRACE; + sig = SIGTRAP; + break; case VEC_TRAP15: /* breakpoint */ + info.si_code = TRAP_BRKPT; sig = SIGTRAP; break; default: + info.si_code = ILL_ILLOPC; sig = SIGILL; break; } - - send_sig (sig, current, 1); -} - -asmlinkage void set_esp0 (unsigned long ssp) -{ - current->tss.esp0 = ssp; + info.si_signo = sig; + info.si_errno = 0; + switch (fp->ptregs.format) { + default: + info.si_addr = (void *) fp->ptregs.pc; + break; + case 2: + info.si_addr = (void *) fp->un.fmt2.iaddr; + break; + case 7: + info.si_addr = (void *) fp->un.fmt7.effaddr; + break; + case 9: + info.si_addr = (void *) fp->un.fmt9.iaddr; + break; + case 10: + info.si_addr = (void *) fp->un.fmta.daddr; + break; + case 11: + info.si_addr = (void *) fp->un.fmtb.daddr; + break; + } + force_sig_info (sig, &info, current); } void die_if_kernel (char *str, struct pt_regs *fp, int nr) diff -ur --new-file old/linux/arch/m68k/mac/Makefile new/linux/arch/m68k/mac/Makefile --- old/linux/arch/m68k/mac/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mac/Makefile Fri Feb 13 01:30:13 1998 @@ -0,0 +1,16 @@ +# +# Makefile for Linux arch/m68k/mac 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... + +EXTRA_CFLAGS := -Wa,-m68020 + +O_TARGET := mac.o +O_OBJS := config.o ksyms.o bootparse.o macints.o via6522.o \ + mackeyb.o adb-bus.o macboing.o debug.o + +include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/arch/m68k/mac/adb-bus.c new/linux/arch/m68k/mac/adb-bus.c --- old/linux/arch/m68k/mac/adb-bus.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mac/adb-bus.c Fri Feb 13 01:30:13 1998 @@ -0,0 +1,2134 @@ +/* + * MACII ADB keyboard handler. + * Copyright (c) 1997 Alan Cox + * + * Derived from code + * Copyright (C) 1996 Paul Mackerras. + * + * MSch (9/97) Partial rewrite of interrupt handler to MacII style + * ADB handshake, based on: + * - Guide to Mac Hardware + * - Guido Koerber's session with a logic analyzer + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "via6522.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MACII /* For now - will be a switch */ + +/* Bits in B data register: all active low */ +#define TREQ 0x08 /* Transfer request (input) */ +#define TACK 0x10 /* Transfer acknowledge (output) */ +#define TIP 0x20 /* Transfer in progress (output) */ + +/* Bits in B data register: ADB transaction states MacII */ +#define ST_MASK 0x30 /* mask for selecting ADB state bits */ +/* ADB transaction states according to GMHW */ +#define ST_CMD 0x00 /* ADB state: command byte */ +#define ST_EVEN 0x10 /* ADB state: even data byte */ +#define ST_ODD 0x20 /* ADB state: odd data byte */ +#define ST_IDLE 0x30 /* ADB state: idle, nothing to send */ + +/* Bits in ACR */ +#define SR_CTRL 0x1c /* Shift register control bits */ +#ifdef USE_ORIG +#define SR_EXT 0x1c /* Shift on external clock */ +#else +#define SR_EXT 0x0c /* Shift on external clock */ +#endif +#define SR_OUT 0x10 /* Shift out if 1 */ + +/* Bits in IFR and IER */ +#define IER_SET 0x80 /* set bits in IER */ +#define IER_CLR 0 /* clear bits in IER */ +#define SR_INT 0x04 /* Shift register full/empty */ +#define SR_DATA 0x08 /* Shift register data */ +#define SR_CLOCK 0x10 /* Shift register clock */ + +static struct adb_handler { + void (*handler)(unsigned char *, int, struct pt_regs *); +} adb_handler[16]; + +static enum adb_state { + idle, + sent_first_byte, + sending, + reading, + read_done, + awaiting_reply +} adb_state; + +static struct adb_request *current_req; +static struct adb_request *last_req; +static unsigned char cuda_rbuf[16]; +static unsigned char *reply_ptr; +static int reply_len; +static int reading_reply; +static int data_index; +static int first_byte; +static int prefix_len; + +static int status = ST_IDLE|TREQ; +static int last_status; +/*static int adb_delay;*/ +int in_keybinit = 1; + +static void adb_start(void); +extern void adb_interrupt(int irq, void *arg, struct pt_regs *regs); +extern void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs); +extern void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs); +extern void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs); +static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs); + +/* + * Misc. defines for testing + */ + +extern int console_loglevel; + +#define ADBDEBUG_STATUS (1) +#define ADBDEBUG_STATE (2) +#define ADBDEBUG_READ (4) +#define ADBDEBUG_WRITE (8) +#define ADBDEBUG_START (16) +#define ADBDEBUG_RETRY (32) +#define ADBDEBUG_POLL (64) +#define ADBDEBUG_INT (128) +#define ADBDEBUG_PROT (256) +#define ADBDEBUG_SRQ (512) +#define ADBDEBUG_REQUEST (1024) +#define ADBDEBUG_INPUT (2048) +#define ADBDEBUG_DEVICE (4096) + + +#define DEBUG_ADB + +#ifdef DEBUG_ADB +#define ADBDEBUG (ADBDEBUG_READ | ADBDEBUG_START | ADBDEBUG_WRITE | ADBDEBUG_SRQ | ADBDEBUG_REQUEST) +#else +#define ADBDEBUG (0) +#endif + +#define TRY_CUDA + +void adb_bus_init(void) +{ + unsigned long flags; + unsigned char c; + + save_flags(flags); + cli(); + + /* + * Setup ADB + */ + + switch(macintosh_config->adb_type) + { + + case MAC_ADB_II: + printk("adb: MacII style keyboard/mouse driver.\n"); + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); + /* + * Docs suggest TREQ should be output - that seems nuts + * BSD agrees here :-) + * Setup vPCR ?? + */ + +#ifdef USE_ORIG + /* Lower the bus signals (MacII is active low it seems ???) */ + via_write(via1, vBufB, via_read(via1, vBufB)&~TACK); +#else + /* Corresponding state: idle (clear state bits) */ + via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); + last_status = (via_read(via1, vBufB)&~ST_MASK); +#endif + /* Shift register on input */ + c=via_read(via1, vACR); + c&=~SR_CTRL; /* Clear shift register bits */ + c|=SR_EXT; /* Shift on external clock; out or in? */ + via_write(via1, vACR, c); + /* Wipe any pending data and int */ + via_read(via1, vSR); + + /* This is interrupts on enable SR for keyboard */ + via_write(via1, vIER, IER_SET|SR_INT); + /* This clears the interrupt bit */ + via_write(via1, vIFR, SR_INT); +#if 0 + ct=1000; + while( ct-- && (via_read(via1, vBufB)&TREQ)) + udelay(1000); + if(ct<0) + printk("No sync occured\n"); + ct=1000; + while( ct-- && !(via_read(via1, vIFR)&SR_INT)) + udelay(1000); + if(ct<0) + printk("No sync 2 occured\n"); + via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1, vBufB)|TACK); + while( ct-- && !(via_read(via1, vBufB)&TREQ)) + udelay(1000); + if(ct<0) + printk("No sync 3 occured\n"); + ct=1000; + while( ct-- && !(via_read(via1, vIFR)&SR_INT)) + udelay(1000); + if(ct<0) + printk("No sync 4 occured\n"); + via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1, vBufB)|TIP); +#endif + /* + * Ok we probably ;) have a ready to use adb bus. Its also + * hopefully idle (Im assuming the mac didnt leave a half + * complete transaction on booting us). + */ + + request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, + "adb interrupt", adb_interrupt); + adb_state = idle; + break; + /* + * Unsupported; but later code doesn't notice !! + */ + case MAC_ADB_CUDA: + printk("adb: CUDA interface.\n"); +#ifdef TRY_CUDA + /* don't know what to set up here ... */ + adb_state = idle; + /* Set the lines up. We want TREQ as input TACK|TIP as output */ + via_write(via1, vDirB, ((via_read(via1,vDirB)|TACK|TIP)&~TREQ)); + request_irq(IRQ_MAC_ADB, adb_cuda_interrupt, IRQ_FLG_LOCK, + "adb CUDA interrupt", adb_cuda_interrupt); + break; +#else + goto nosupp; +#endif + case MAC_ADB_IISI: + printk("adb: Using IIsi hardware.\n"); + goto nosupp; + default: + printk("adb: Unknown hardware interface.\n"); + nosupp: + printk("adb: Interface unsupported.\n"); + restore_flags(flags); + return; + } + + /* + * XXX: interrupt only registered if supported HW !! + * -> unsupported HW will just time out on keyb_init! + */ +#if 0 + request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, + "adb interrupt", adb_interrupt); +#endif +#ifdef DEBUG_ADB_INTS + request_irq(IRQ_MAC_ADB_CL, adb_clock_interrupt, IRQ_FLG_LOCK, + "adb clock interrupt", adb_clock_interrupt); + request_irq(IRQ_MAC_ADB_SD, adb_data_interrupt, IRQ_FLG_LOCK, + "adb data interrupt", adb_data_interrupt); +#endif + + printk("adb: init done.\n"); + restore_flags(flags); +} + +#define WAIT_FOR(cond, what) \ + do { \ + for (x = 1000; !(cond); --x) { \ + if (x == 0) { \ + printk("Timeout waiting for " what); \ + return 0; \ + } \ + __delay(100*160); \ + } \ + } while (0) + +/* + * Construct and send an adb request + * This function is the main entry point into the ADB driver from + * kernel code; it takes the request data supplied and populates the + * adb_request structure. + * In order to keep this interface independent from any assumption about + * the underlying ADB hardware, we take requests in CUDA format here, + * the ADB packet 'prefixed' with a packet type code. + * Non-CUDA hardware is confused by this, so we strip the packet type + * here depending on hardware type ... + */ +int adb_request(struct adb_request *req, void (*done)(struct adb_request *), + int nbytes, ...) +{ + va_list list; + int i, start; + + va_start(list, nbytes); + + /* + * skip first byte if not CUDA + */ + if (macintosh_config->adb_type != MAC_ADB_CUDA) { + start = va_arg(list, int); + nbytes--; + } + req->nbytes = nbytes; + req->done = done; +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk("adb_request, data bytes: "); +#endif + for (i = 0; i < nbytes; ++i) { + req->data[i] = va_arg(list, int); +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk("%x ", req->data[i]); +#endif + } +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk(" !\n"); +#endif + va_end(list); + /* + * XXX: This might be fatal if no reply is generated (i.e. Listen) ! + * Currently, the interrupt handler 'fakes' a reply on non-TALK + * commands for this reason. + * Also, we need a CUDA_AUTOPOLL emulation here for non-CUDA + * Macs, and some mechanism to remember the last issued TALK + * request for resending it repeatedly on timeout! + */ + req->reply_expected = 1; + return adb_send_request(req); +} + +/* + * Construct an adb request for later sending + * This function only populates the adb_request structure, without + * actually queueing it. + * Reason: Poll requests and Talk requests need to be handled in a way + * different from 'user' requests; no reply_expected is set and + * Poll requests need to be placed at the head of the request queue. + * Using adb_request results in implicit queueing at the tail of the + * request queue (duplicating the Poll) with reply_expected set. + * No adjustment of packet data is necessary, as this mechanisnm is not + * used by CUDA hardware (Autopoll used instead). + */ +int adb_build_request(struct adb_request *req, void (*done)(struct adb_request *), + int nbytes, ...) +{ + va_list list; + int i; + + req->nbytes = nbytes; + req->done = done; + va_start(list, nbytes); +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk("adb__build_request, data bytes: "); +#endif + /* + * skip first byte if not CUDA ? + */ + for (i = 0; i < nbytes; ++i) { + req->data[i] = va_arg(list, int); +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk("%x ", req->data[i]); +#endif + } +#if (ADBDEBUG & ADBDEBUG_REQUEST) + if (console_loglevel == 10) + printk(" !\n"); +#endif + va_end(list); + + req->reply_expected = 0; + return 0; +} + +/* + * Send an ADB poll (Talk, tagged on the front of the request queue) + */ +void adb_queue_poll(void) +{ + static int pod=0; + static int in_poll=0; + static struct adb_request r; + unsigned long flags; + + if(in_poll) + printk("Double poll!\n"); + + in_poll++; + pod++; + if(pod>7) /* 15 */ + pod=0; + +#if (ADBDEBUG & ADBDEBUG_POLL) + if (console_loglevel == 10) + printk("adb: Polling %d\n",pod); +#endif + + /* XXX: that's a TALK, register 0, MacII version */ + adb_build_request(&r,NULL, 1, (pod<<4|0xC)); + + r.reply_expected=0; + r.done=NULL; + r.sent=0; + r.got_reply=0; + r.reply_len=0; + save_flags(flags); + cli(); + /* Poll inserted at head of queue ... */ + r.next=current_req; + current_req=&r; + restore_flags(flags); + adb_start(); + in_poll--; +} + +/* + * Send an ADB retransmit (Talk, appended to the request queue) + */ +void adb_retransmit(int device) +{ + static int in_retransmit=0; + static struct adb_request rt; + unsigned long flags; + + if(in_retransmit) + printk("Double retransmit!\n"); + + in_retransmit++; + +#if (ADBDEBUG & ADBDEBUG_POLL) + if (console_loglevel == 10) + printk("adb: Sending retransmit: %d\n", device); +#endif + + /* MacII version */ + adb_build_request(&rt,NULL, 1, (device<<4|0xC)); + + rt.reply_expected = 0; + rt.done = NULL; + rt.sent = 0; + rt.got_reply = 0; + rt.reply_len = 0; + rt.next = NULL; + + save_flags(flags); + cli(); + + /* Retransmit inserted at tail of queue ... */ + + if (current_req != NULL) + { + last_req->next = &rt; + last_req = &rt; + } + else + { + current_req = &rt; + last_req = &rt; + } + + /* always restart driver (send_retransmit used in place of adb_start!)*/ + + if (adb_state == idle) + adb_start(); + + restore_flags(flags); + in_retransmit--; +} + +/* + * Queue an ADB request; start ADB transfer if necessary + */ +int adb_send_request(struct adb_request *req) +{ + unsigned long flags; + + req->next = 0; + req->sent = 0; + req->got_reply = 0; + req->reply_len = 0; + save_flags(flags); + cli(); + + if (current_req != NULL) + { + last_req->next = req; + last_req = req; + } + else + { + current_req = req; + last_req = req; + if (adb_state == idle) + adb_start(); + } + + restore_flags(flags); + return 0; +} + +static int nclock, ndata; + +static int need_poll = 0; +static int command_byte = 0; +static int last_reply = 0; +static int last_active = 0; + +static struct adb_request *retry_req; + +/* + * Start sending ADB packet + */ +static void adb_start(void) +{ + unsigned long flags; + struct adb_request *req; + + /* + * We get here on three 'sane' conditions: + * 1) called from send_adb_request, if adb_state == idle + * 2) called from within adb_interrupt, if adb_state == idle + * (after receiving, or after sending a LISTEN) + * 3) called from within adb_interrupt, if adb_state == sending + * and no reply is expected (immediate next command). + * Maybe we get here on SRQ as well ?? + */ + + /* get the packet to send */ + req = current_req; + /* assert adb_state == idle */ + if (adb_state != idle) { + printk("ADB: adb_start called while driver busy (%p %x %x)!\n", + req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); + return; + } + if (req == 0) + return; + save_flags(flags); + cli(); + +#if (ADBDEBUG & ADBDEBUG_START) + if (console_loglevel == 10) + printk("adb_start: request %p ", req); +#endif + + nclock = 0; + ndata = 0; + + /* + * IRQ signaled ?? (means ADB controller wants to send, or might + * be end of packet if we were reading) + */ + if ((via_read(via1, vBufB)& TREQ) == 0) + { + switch(macintosh_config->adb_type) + { + /* + * FIXME - we need to restart this on a timer + * or a collision at boot hangs us. + * Never set adb_state to idle here, or adb_start + * won't be called again from send_request! + * (need to re-check other cases ...) + */ + case MAC_ADB_CUDA: + /* printk("device busy - fail\n"); */ + restore_flags(flags); + /* a byte is coming in from the CUDA */ + return; + case MAC_ADB_II: + /* + * if the interrupt handler set the need_poll + * flag, it's hopefully a SRQ poll or re-Talk + * so we try to send here anyway + */ + if (!need_poll) { + printk("device busy - retry %p state %d status %x!\n", + req, adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); + retry_req = req; + /* set ADB status here ? */ + restore_flags(flags); + return; + } else { +#if (ADBDEBUG & ADBDEBUG_START) + if (console_loglevel == 10) + printk("device busy - polling; state %d status %x!\n", + adb_state, via_read(via1, vBufB)&(ST_MASK|TREQ)); +#endif + need_poll = 0; + break; + } + } + } + +#if 0 + /* + * Bus idle ?? Not sure about this one; SRQ might need ST_CMD here! + * OTOH: setting ST_CMD in the interrupt routine would make the + * ADB contoller shift in before this routine starts shifting out ... + */ + if ((via_read(via1, vBufB)&ST_MASK) != ST_IDLE) + { +#if (ADBDEBUG & ADBDEBUG_STATE) + if (console_loglevel == 10) + printk("ADB bus not idle (%x), retry later!\n", + via_read(via1, vBufB)&(ST_MASK|TREQ)); +#endif + retry_req = req; + restore_flags(flags); + return; + } +#endif + + /* + * Another retry pending? (sanity check) + */ + if (retry_req) { +#if (ADBDEBUG & ADBDEBUG_RETRY) + if (console_loglevel == 10) + if (retry_req == req) + /* new requests are appended at tail of request queue */ + printk("adb_start: retry %p pending ! \n", req); + else + /* poll requests are added to the head of queue */ + printk("adb_start: retry %p pending, req %p (poll?) current! \n", + retry_req, req); +#endif + retry_req = NULL; + } + + /* + * Seems OK, go for it! + */ + switch(macintosh_config->adb_type) + { + case MAC_ADB_CUDA: + /* store command byte (first byte is 'type' byte) */ + command_byte = req->data[1]; + /* set the shift register to shift out and send a byte */ + via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); + via_write(via1, vSR, req->data[0]); + via_write(via1, vBufB, via_read(via1, vBufB)&~TIP); + break; + case MAC_ADB_II: + /* store command byte */ + command_byte = req->data[0]; + /* Output mode */ + via_write(via1, vACR, via_read(via1, vACR)|SR_OUT); + /* Load data */ + via_write(via1, vSR, req->data[0]); +#ifdef USE_ORIG + /* Turn off TIP/TACK - this should tell the external logic to + start the external shift clock */ +/* via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK));*/ + via_write(via1, vBufB, via_read(via1, vBufB)|(TIP|TACK)); +#else + /* set ADB state to 'command' */ + via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_CMD); +#endif + break; + } +#if (ADBDEBUG & ADBDEBUG_START) + if (console_loglevel == 10) + printk("sent first byte of %d: %x, (%x %x) ... ", + req->nbytes, req->data[0], adb_state, + (via_read(via1, vBufB) & (ST_MASK|TREQ)) ); +#endif + adb_state = sent_first_byte; + data_index = 1; + restore_flags(flags); +} + +/* + * Poll the ADB state (maybe obsolete now that interrupt-driven ADB runs) + */ +void adb_poll(void) +{ + unsigned char c; + unsigned long flags; + save_flags(flags); + cli(); + c=via_read(via1, vIFR); +#if (ADBDEBUG & ADBDEBUG_POLL) +#ifdef DEBUG_ADB_INTS + if (console_loglevel == 10) { + printk("adb_poll: IFR %x state %x cl %d dat %d ", + c, adb_state, nclock, ndata); + if (c & (SR_CLOCK|SR_DATA)) { + if (c & SR_CLOCK) + printk("adb clock event "); + if (c & SR_DATA) + printk("adb data event "); + } + } +#else + if (console_loglevel == 10) + printk("adb_poll: IFR %x state %x ", + c, adb_state); +#endif + if (console_loglevel == 10) + printk("\r"); +#endif + if (c & SR_INT) + { +#if (ADBDEBUG & ADBDEBUG_POLL) + if (console_loglevel == 10) + printk("adb_poll: adb interrupt event\n"); +#endif + adb_interrupt(0, 0, 0); + } + restore_flags(flags); +} + +/* + * Debugging gimmicks + */ +void adb_clock_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + nclock++; +} + +void adb_data_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + ndata++; +} + +/* + * The notorious ADB interrupt handler - does all of the protocol handling, + * except for starting new send operations. Relies heavily on the ADB + * controller sending and receiving data, thereby generating SR interrupts + * for us. This means there has to be always activity on the ADB bus, otherwise + * the whole process dies and has to be re-kicked by sending TALK requests ... + * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type + * ADB the problem isn't solved yet (retransmit of the latest active TALK seems + * a good choice; either on timeout or on a timer interrupt). + * + * The basic ADB state machine was left unchanged from the original MacII code + * by Alan Cox, which was based on the CUDA driver for PowerMac. + * The syntax of the ADB status lines seems to be totally different on MacII, + * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for + * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start + * and end of a receive packet are signaled by asserting /IRQ on the interrupt + * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on + * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the + * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB + * protocol with a logic analyzer!!) + * CUDA seems to use /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP|TACK + * for sending, and /TIP -> /TIP | TACK -> /TIP -> /TIP | TACK ... -> TIP for + * receiving. No clue how timeouts are handled; SRQ seems to be sent as a + * separate packet. Quite a few changes have been made outside the handshake + * code, so I don't know if the CUDA code still behaves as before. + * + * Note: As of 21/10/97, the MacII ADB part works including timeout detection + * and retransmit (Talk to the last active device). Cleanup of code and + * testing of the CUDA functionality is required, though. + * Note2: As of 13/12/97, CUDA support is definitely broken ... + * Next TODO: implementation of IIsi ADB protocol (maybe the USE_ORIG + * conditionals can be a start?) + */ +void adb_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + int x, adbdir; + struct adb_request *req; + + last_status = status; + +#ifdef USE_ORIG + status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); +#else + if (macintosh_config->adb_type==MAC_ADB_CUDA) + status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); + else + /* status bits (0x8->0x20) and direction (0x10 ??) CLASH !! */ + status = (via_read(via1, vBufB) & (ST_MASK|TREQ)); +#endif + adbdir = (via_read(via1, vACR) & SR_OUT); +#if (ADBDEBUG & ADBDEBUG_INT) + if (console_loglevel == 10) + printk("adb_interrupt: state=%d status=%x last=%x direction=%x\n", + adb_state, status, last_status, adbdir); +#endif + + + switch (adb_state) + { + case idle: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + /* CUDA has sent us the first byte of data - unsolicited */ + if (status != TREQ) + printk("cuda: state=idle, status=%x\n", status); + x = via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1,vBufB)&~TIP); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { +#if (ADBDEBUG & ADBDEBUG_STATUS) + if (status == TREQ && !adbdir) + /* that's: not IRQ, idle, input -> weird */ + printk("adb_macII: idle, status=%x dir=%x\n", + status, adbdir); +#endif + x = via_read(via1, vSR); + first_byte = x; +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk("adb_macII: receiving unsol. packet: %x (%x %x) ", + x, adb_state, status); +#endif +#ifdef USE_ORIG + via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); +#else + /* set ADB state = even for first data byte */ + via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); +#endif + } + adb_state = reading; + reply_ptr = cuda_rbuf; + reply_len = 0; + reading_reply = 0; + prefix_len = 0; + if (macintosh_config->adb_type==MAC_ADB_II) { + *reply_ptr++ = ADB_PACKET; + *reply_ptr++ = first_byte; + *reply_ptr++ = command_byte; /*first_byte;*/ + reply_len = 3; + prefix_len = 3; + } + break; + + case awaiting_reply: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + /* CUDA has sent us the first byte of data of a reply */ + if (status != TREQ) + printk("cuda: state=awaiting_reply, status=%x\n", status); + x = via_read(via1, vSR); + via_write(via1,vBufB, + via_read(via1, vBufB)&~TIP); + } else if(macintosh_config->adb_type==MAC_ADB_II) { + /* handshake etc. for II ?? */ + x = via_read(via1, vSR); + first_byte = x; +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk("adb_macII: reading reply: %x (%x %x) ", + x, adb_state, status); +#endif +#ifdef USE_ORIG + via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); +#else + /* set ADB state = even for first data byte */ + via_write(via1, vBufB, (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); +#endif + } + adb_state = reading; + reply_ptr = current_req->reply; + reading_reply = 1; + reply_len = 0; + prefix_len = 0; + if (macintosh_config->adb_type==MAC_ADB_II) { + *reply_ptr++ = ADB_PACKET; + *reply_ptr++ = first_byte; + *reply_ptr++ = first_byte; /* should be command byte */ + reply_len = 3; + prefix_len = 3; + } + break; + + case sent_first_byte: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + if (status == TREQ + TIP + SR_OUT) + { + /* collision */ + via_write(via1, vACR, + via_read(via1, vACR)&~SR_OUT); + x = via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1,vBufB)|TIP|TACK); + adb_state = idle; + } + else + { + /* assert status == TIP + SR_OUT */ + if (status != TIP + SR_OUT) + printk("cuda: state=sent_first_byte status=%x\n", status); + via_write(via1,vSR,current_req->data[1]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + data_index = 2; + adb_state = sending; + } + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + /* how to detect a collision here ?? */ +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk(" sending: %x (%x %x) ", + current_req->data[1], adb_state, status); +#endif + /* maybe we're already done (Talk, or Poll)? */ + if (data_index >= current_req->nbytes) + { + /* assert it's a Talk ?? */ + if ( (command_byte&0xc) != 0xc + && console_loglevel == 10 ) + printk("ADB: single byte command, no Talk: %x!\n", + command_byte); +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk(" -> end (%d of %d) (%x %x)!\n", + data_index, current_req->nbytes, adb_state, status); +#endif + current_req->sent = 1; + if (current_req->reply_expected) + { +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk("ADB: reply expected on poll!\n"); +#endif + adb_state = awaiting_reply; + reading_reply = 0; + } else { +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk("ADB: no reply for poll, not calling done()!\n"); +#endif + req = current_req; + current_req = req->next; +#if 0 /* XXX Not sure about that one ... probably better enabled */ + if (req->done) + (*req->done)(req); +#endif + adb_state = idle; + reading_reply = 0; + } + /* set to shift in */ + via_write(via1, vACR, + via_read(via1, vACR) & ~SR_OUT); + x=via_read(via1, vSR); +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); +#else + /* set ADB state idle - might get SRQ */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#endif + break; + } +#if (ADBDEBUG & ADBDEBUG_STATUS) + if(!(status==(ST_CMD|TREQ) && adbdir == SR_OUT)) + printk("adb_macII: sent_first_byte, weird status=%x dir=%x\n", + status, adbdir); +#endif + /* SR already set to shift out; send byte */ + via_write(via1, vSR, current_req->data[1]); +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); +#else + /* set state to ST_EVEN (first byte was: ST_CMD) */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); +#endif + data_index=2; + adb_state = sending; + } + break; + + case sending: + req = current_req; + if (data_index >= req->nbytes) + { + /* end of packet */ + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + via_write(via1, vACR, + via_read(via1, vACR)&~SR_OUT); + x = via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1,vBufB)|TACK|TIP); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + /* + * XXX Not sure: maybe only switch to + * input mode on Talk ?? + */ +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk(" -> end (%d of %d) (%x %x)!\n", + data_index-1, req->nbytes, adb_state, status); +#endif + /* set to shift in */ + via_write(via1, vACR, + via_read(via1, vACR) & ~SR_OUT); + x=via_read(via1, vSR); +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); +#else + /* set ADB state idle - might get SRQ */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#endif + } + req->sent = 1; + if (req->reply_expected) + { + /* + * maybe fake a reply here on Listen ?? + * Otherwise, a Listen hangs on success + */ + if ( ((req->data[0]&0xc) == 0xc) ) + adb_state = awaiting_reply; + else { + /* + * Reply expected, but none + * possible -> fake reply. + * Problem: sending next command + * should probably be done + * without setting bus to 'idle'! + * (except if no more commands) + */ +#if (ADBDEBUG & ADBDEBUG_PROT) + printk("ADB: reply expected on Listen, faking reply\n"); +#endif + /* make it look weird */ + /* XXX: return reply_len -1? */ + /* XXX: fake ADB header? */ + req->reply[0] = req->reply[1] = req->reply[2] = 0xFF; + req->reply_len = 3; + req->got_reply = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); + /* + * ready with this one, run + * next command or repeat last + * Talk (=idle on II) + */ + /* set state to idle !! */ + adb_state = idle; + if (current_req || retry_req) + adb_start(); + } + } + else + { + current_req = req->next; + if (req->done) + (*req->done)(req); + /* not sure about this */ + /* + * MS: Must set idle, no new request + * started else ! + */ + adb_state = idle; + /* + * requires setting ADB state to idle, + * maybe read a byte ! (done above) + */ + if (current_req || retry_req) + adb_start(); + } + } + else + { + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + via_write(via1, vSR, req->data[data_index++]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { +#if (ADBDEBUG & ADBDEBUG_WRITE) + if (console_loglevel == 10) + printk(" %x (%x %x) ", + req->data[data_index], adb_state, status); +#endif + via_write(via1, vSR, req->data[data_index++]); +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); +#else + /* invert state bits, toggle ODD/EVEN */ + x = via_read(via1, vBufB); + via_write(via1, vBufB, + (x&~ST_MASK)|~(x&ST_MASK)); +#endif + } + } + break; + + case reading: +#ifdef POLL_ON_TIMEOUT + if((reply_len-prefix_len)==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) +#else + if( (first_byte == 0xFF && (reply_len-prefix_len)==2 + && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || + ((reply_len-prefix_len)==3 + && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)) +#endif + { + /* + * possible timeout (in fact, most probably a + * timeout, since SRQ can't be signaled without + * transfer on the bus). + * The last three bytes seen were FF, together + * with the starting byte (in case we started + * on 'idle' or 'awaiting_reply') this probably + * makes four. So this is mostl likely #5! + * The timeout signal is a pattern 1 0 1 0 0.. + * on /INT, meaning we missed it :-( + */ + x = via_read(via1, vSR); + if (x != 0xFF) + printk("ADB: mistaken timeout/SRQ!\n"); + + /* + * ADB status bits: either even or odd. + * adb_state: need to set 'idle' here. + * Maybe saner: set 'need_poll' or + * 'need_resend' here, fall through to + * read_done ?? + */ +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk(" -> read aborted: %x (%x %x)!\n", + x, adb_state, status); +#endif + +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); +#else +#if 0 /* XXX leave status unchanged!! - need to check this again! */ + /* set ADB state to idle (required by adb_start()) */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#endif +#endif + + /* + * What if the timeout happens on reading a + * reply ?? Assemble error reply and call + * current_request->done()? Keep request + * on queue? + */ + + /* prevent 'busy' in adb_start() */ + need_poll = 1; + + /* + * Timeout: /IRQ alternates high/low during + * 4 'FF' bytes (1 0 1 0 0...) + * We're on byte 5, so we need one + * more backlog here (TBI) .... + */ + if ((status&TREQ) != (last_status&TREQ)) { +#if (ADBDEBUG & ADBDEBUG_SRQ) + if (console_loglevel == 10) + printk("ADB: reply timeout, resending!\n"); +#endif + /* + * first byte received should be the + * command byte timing out !! + */ + if (first_byte != 0xff) + command_byte = first_byte; + + /* + * compute target for retransmit: if + * last_active is set, use that one, + * else use command_byte + */ + if (last_active == -1) + last_active = (command_byte&0xf0)>>4; + adb_state = idle; + /* resend if TALK, don't poll! */ + if (current_req) + adb_start(); + else + /* + * XXX: need to count the timeouts ?? + * restart last active TALK ?? + * If no current_req, reuse old one! + */ + adb_retransmit(last_active); + + } else { + /* + * SRQ: NetBSD suggests /IRQ is asserted!? + */ + if (status&TREQ) + printk("ADB: SRQ signature w/o /INT!\n"); +#if (ADBDEBUG & ADBDEBUG_SRQ) + if (console_loglevel == 10) + printk("ADB: empty SRQ packet!\n"); +#endif + /* Terminate the SRQ packet and poll */ + adb_state = idle; + adb_queue_poll(); + } + /* + * Leave ADB status lines unchanged (means /IRQ + * will still be low when entering adb_start!) + */ + break; + } + if((reply_len-prefix_len)>3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) + { + /* SRQ tacked on data packet */ + /* Check /IRQ here ?? */ +#if (ADBDEBUG & ADBDEBUG_SRQ) + if (console_loglevel == 10) + printk("\nADB: Packet with SRQ!\n"); +#endif + /* Terminate the packet (SRQ never ends) */ + x = via_read(via1, vSR); + adb_state = read_done; + reply_len -= 3; + reply_ptr -= 3; + need_poll = 1; + /* need to continue; next byte not seen else */ + /* + * XXX: not at all sure here; maybe need to + * send away the reply and poll immediately? + */ + } else { + /* Sanity check */ + if(reply_len>15) + reply_len=0; + /* read byte */ + *reply_ptr = via_read(via1, vSR); + x = *reply_ptr; +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk(" %x (%x %x) ", + *reply_ptr, adb_state, status); +#endif + reply_ptr++; + reply_len++; + } + /* The usual handshake ... */ + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + if (status == TIP) + { + /* that's all folks */ + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); + adb_state = read_done; + } + else + { + /* assert status == TIP | TREQ */ + if (status != TIP + TREQ) + printk("cuda: state=reading status=%x\n", status); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + } + if(macintosh_config->adb_type==MAC_ADB_II) + { + /* + * NetBSD hints that the next to last byte + * is sent with IRQ !! + * Guido found out it's the last one (0x0), + * but IRQ should be asserted already. + * Problem with timeout detection: First + * transition to /IRQ might be second + * byte of timeout packet! + * Timeouts are signaled by 4x FF. + */ + if(!(status&TREQ) && x == 0x00) /* != 0xFF */ + { +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk(" -> read done!\n"); +#endif +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); +#else +#if 0 /* XXX: we take one more byte (why?), so handshake! */ + /* set ADB state to idle */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#else + /* invert state bits, toggle ODD/EVEN */ + x = via_read(via1, vBufB); + via_write(via1, vBufB, + (x&~ST_MASK)|~(x&ST_MASK)); +#endif +#endif + /* adjust packet length */ + reply_len--; + reply_ptr--; + adb_state = read_done; + } + else + { +#if (ADBDEBUG & ADBDEBUG_STATUS) + if(status!=TIP+TREQ) + printk("macII_adb: state=reading status=%x\n", status); +#endif +#ifdef USE_ORIG + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); +#else + /* not caught: ST_CMD */ + /* required for re-entry 'reading'! */ + if ((status&ST_MASK) == ST_IDLE) { + /* (in)sanity check - set even */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_EVEN); + } else { + /* invert state bits, toggle ODD/EVEN */ + x = via_read(via1, vBufB); + via_write(via1, vBufB, + (x&~ST_MASK)|~(x&ST_MASK)); + } +#endif + } + } + break; + + case read_done: + x = via_read(via1, vSR); +#if (ADBDEBUG & ADBDEBUG_READ) + if (console_loglevel == 10) + printk("ADB: read done: %x (%x %x)!\n", + x, adb_state, status); +#endif + if (reading_reply) + { + req = current_req; + req->reply_len = reply_ptr - req->reply; + req->got_reply = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); + } + else + { + adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs); + } + + /* + * remember this device ID; it's the latest we got a + * reply from! + */ + last_reply = command_byte; + last_active = (command_byte&0xf0)>>4; + + + /* + * Assert status = ST_IDLE ?? + */ + /* + * SRQ seen before, initiate poll now + */ + if (need_poll) { +#if (ADBDEBUG & ADBDEBUG_POLL) + if (console_loglevel == 10) + printk("ADB: initiate poll!\n"); +#endif + adb_state = idle; + /* + * set ADB status bits?? (unchanged above!) + */ + adb_queue_poll(); + need_poll = 0; + /* hope this is ok; queue_poll runs adb_start */ + break; + } + +#ifdef USE_ORIG + /* + * This will fail - TREQ is active low -> 0 is IRQ !! + */ + if (status == TREQ) + { + via_write(via1, vBufB, + via_read(via1, vBufB)|~TIP); +#else + /* + * /IRQ seen, so the ADB controller has data for us + */ + if (!(status&TREQ)) + { + /* set ADB state to idle */ + via_write(via1, vBufB, + (via_read(via1, vBufB)&~ST_MASK)|ST_IDLE); +#endif + adb_state = reading; + reply_ptr = cuda_rbuf; + reply_len = 0; + prefix_len = 0; + if (macintosh_config->adb_type==MAC_ADB_II) { + *reply_ptr++ = ADB_PACKET; + *reply_ptr++ = command_byte; + reply_len = 2; + prefix_len = 2; + } + reading_reply = 0; + } + else + { + /* + * no IRQ, send next packet or wait + */ + adb_state = idle; + if (current_req) + adb_start(); + else + adb_retransmit(last_active); + } + break; + + default: +#if (ADBDEBUG & ADBDEBUG_STATE) + printk("adb_interrupt: unknown adb_state %d?\n", adb_state); +#endif + } +} + +/* + * Restart of CUDA support: please modify this interrupt handler while + * working at the Quadra etc. ADB driver. We can try to merge them later, or + * remove the CUDA stuff from the MacII handler + */ + +void adb_cuda_interrupt(int irq, void *arg, struct pt_regs *regs) +{ + int x, status; + struct adb_request *req; + + status = (~via_read(via1, vBufB) & (TIP|TREQ)) | (via_read(via1, vACR) & SR_OUT); + if (console_loglevel == 10) + printk("adb_interrupt: state=%d status=%x\n", adb_state, status); + + switch (adb_state) + { + case idle: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + /* CUDA has sent us the first byte of data - unsolicited */ + if (status != TREQ) + printk("cuda: state=idle, status=%x want=%x\n", + status, TREQ); + x = via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1,vBufB)&~TIP); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + if (status != TREQ) + printk("adb_macII: state=idle status=%x want=%x\n", + status, TREQ); + x = via_read(via1, vSR); + via_write(via1, vBufB, via_read(via1, vBufB)&~(TIP|TACK)); + } + adb_state = reading; + reply_ptr = cuda_rbuf; + reply_len = 0; + reading_reply = 0; + break; + + case awaiting_reply: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + /* CUDA has sent us the first byte of data of a reply */ + if (status != TREQ) + printk("cuda: state=awaiting_reply, status=%x want=%x\n", + status, TREQ); + x = via_read(via1, vSR); + via_write(via1,vBufB, + via_read(via1, vBufB)&~TIP); + } + adb_state = reading; + reply_ptr = current_req->reply; + reading_reply = 1; + reply_len = 0; + break; + + case sent_first_byte: + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + if (status == TREQ + TIP + SR_OUT) + { + /* collision */ + if (console_loglevel == 10) + printk("cuda: send collision!\n"); + via_write(via1, vACR, + via_read(via1, vACR)&~SR_OUT); + x = via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1,vBufB)|TIP|TACK); + adb_state = idle; + } + else + { + /* assert status == TIP + SR_OUT */ + if (status != TIP + SR_OUT) + printk("cuda: state=sent_first_byte status=%x want=%x\n", + status, TIP + SR_OUT); + via_write(via1,vSR,current_req->data[1]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + data_index = 2; + adb_state = sending; + } + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + if(status!=TIP+SR_OUT) + printk("adb_macII: state=send_first_byte status=%x want=%x\n", + status, TIP+SR_OUT); + via_write(via1, vSR, current_req->data[1]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + data_index=2; + adb_state = sending; + } + break; + + case sending: + req = current_req; + if (data_index >= req->nbytes) + { + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + via_write(via1, vACR, + via_read(via1, vACR)&~SR_OUT); + x = via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1,vBufB)|TACK|TIP); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + via_write(via1, vACR, + via_read(via1, vACR) & ~SR_OUT); + x=via_read(via1, vSR); + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); + } + req->sent = 1; + if (req->reply_expected) + { + adb_state = awaiting_reply; + } + else + { + current_req = req->next; + if (req->done) + (*req->done)(req); + /* not sure about this */ + adb_state = idle; + adb_start(); + } + } + else + { + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + via_write(via1, vSR, req->data[data_index++]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + else if(macintosh_config->adb_type==MAC_ADB_II) + { + via_write(via1, vSR, req->data[data_index++]); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + } + break; + + case reading: + if(reply_len==3 && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) + { + /* Terminate the SRQ packet */ + printk("CUDA: Got an SRQ\n"); + adb_state = idle; + adb_queue_poll(); + break; + } + /* Sanity check - botched in orig. code! */ + if(reply_len>15) { + printk("CUDA: reply buffer overrun!\n"); + /* wrap buffer */ + reply_len=0; + if (reading_reply) + reply_ptr = current_req->reply; + else + reply_ptr = cuda_rbuf; + } + *reply_ptr = via_read(via1, vSR); + if (console_loglevel == 10) + printk(" %p-> %x (%x %x) ", + reply_ptr, *reply_ptr, adb_state, status); + reply_ptr++; + reply_len++; + if(macintosh_config->adb_type==MAC_ADB_CUDA) + { + if (status == TIP) + { + /* that's all folks */ + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); + adb_state = read_done; + } + else + { + /* assert status == TIP | TREQ */ + if (status != TIP + TREQ) + printk("cuda: state=reading status=%x want=%x\n", + status, TIP + TREQ); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + } + if(macintosh_config->adb_type==MAC_ADB_II) + { + if( status == TIP) + { + via_write(via1, vBufB, + via_read(via1, vBufB)|TACK|TIP); + adb_state = read_done; + } + else + { + if(status!=TIP+TREQ) + printk("macII_adb: state=reading status=%x\n", status); + via_write(via1, vBufB, + via_read(via1, vBufB)^TACK); + } + } + break; + + case read_done: + x = via_read(via1, vSR); + if (reading_reply) + { + req = current_req; + req->reply_len = reply_ptr - req->reply; + req->got_reply = 1; + current_req = req->next; + if (req->done) + (*req->done)(req); + } + else + { + adb_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs); + } + + if (status == TREQ) + { + via_write(via1, vBufB, + via_read(via1, vBufB)|~TIP); + adb_state = reading; + reply_ptr = cuda_rbuf; + reading_reply = 0; + } + else + { + adb_state = idle; + adb_start(); + } + break; + + default: + printk("adb_interrupt: unknown adb_state %d?\n", adb_state); + } +} + +/* + * The 'reply delivery' routine; determines which device sent the + * request and calls the appropriate handler. + * Reply data are expected in CUDA format (again, argh...) so we need + * to fake this in the interrupt handler for MacII. + * Only one handler per device ID is currently possible. + * XXX: is the ID field here representing the default or real ID? + */ +static void adb_input(unsigned char *buf, int nb, struct pt_regs *regs) +{ + int i, id; + + switch (buf[0]) + { + case ADB_PACKET: + /* what's in buf[1] ?? */ + id = buf[2] >> 4; +#if 0 + xmon_printf("adb packet: "); + for (i = 0; i < nb; ++i) + xmon_printf(" %x", buf[i]); + xmon_printf(", id = %d\n", id); +#endif +#if (ADBDEBUG & ADBDEBUG_INPUT) + if (console_loglevel == 10) { + printk("adb_input: adb packet "); + for (i = 0; i < nb; ++i) + printk(" %x", buf[i]); + printk(", id = %d\n", id); + } +#endif + if (adb_handler[id].handler != 0) + { + (*adb_handler[id].handler)(buf, nb, regs); + } + break; + + default: +#if (ADBDEBUG & ADBDEBUG_INPUT) + if (console_loglevel == 10) { + printk("adb_input: data from via (%d bytes):", nb); + for (i = 0; i < nb; ++i) + printk(" %.2x", buf[i]); + printk("\n"); + } +#endif + } +} + +/* Ultimately this should return the number of devices with + the given default id. */ + +int adb_register(int default_id, + void (*handler)(unsigned char *, int, struct pt_regs *)) +{ + if (adb_handler[default_id].handler != 0) + panic("Two handlers for ADB device %d\n", default_id); + adb_handler[default_id].handler = handler; + return 1; +} + +/* + * /dev/adb device driver. + */ + +#define ADB_MAJOR 56 /* major number for /dev/adb */ + +#define ADB_MAX_MINOR 64 /* range of ADB minors */ +#define ADB_TYPE_SHIFT 4 /* # bits for device ID/type in subdevices */ + +#define ADB_TYPE_RAW 0 /* raw device; unbuffered */ +#define ADB_TYPE_BUFF 1 /* raw device; buffered */ +#define ADB_TYPE_COOKED 2 /* 'cooked' device */ + + +extern void adbdev_init(void); + +struct adbdev_state { + struct adb_request req; +}; + +static struct wait_queue *adb_wait; + +static int adb_wait_reply(struct adbdev_state *state, struct file *file) +{ + int ret = 0; + struct wait_queue wait = { current, NULL }; + + add_wait_queue(&adb_wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (!state->req.got_reply) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&adb_wait, &wait); + + return ret; +} + +static void adb_write_done(struct adb_request *req) +{ + if (!req->got_reply) { + req->reply_len = 0; + req->got_reply = 1; + } + wake_up_interruptible(&adb_wait); +} + +struct file_operations *adb_raw[16]; +struct file_operations *adb_buffered[16]; +struct file_operations *adb_cooked[16]; + +static int adb_open(struct inode *inode, struct file *file) +{ + int adb_type, adb_subtype; + struct adbdev_state *state; + + if (MINOR(inode->i_rdev) > ADB_MAX_MINOR) + return -ENXIO; + + switch (MINOR(inode->i_rdev) >> ADB_TYPE_SHIFT) { + case ADB_TYPE_RAW: + /* see code below */ + break; + case ADB_TYPE_BUFF: + /* TBI */ + return -ENXIO; + case ADB_TYPE_COOKED: + /* subtypes such as kbd, mouse, ... */ + adb_subtype = MINOR(inode->i_rdev) & ~ADB_TYPE_SHIFT; + if ((file->f_op = adb_cooked[adb_subtype])) + return file->f_op->open(inode,file); + else + return -ENODEV; + } + + state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); + if (state == 0) + return -ENOMEM; + file->private_data = state; + state->req.reply_expected = 0; + return 0; +} + +static void adb_release(struct inode *inode, struct file *file) +{ + struct adbdev_state *state = file->private_data; + + if (state) { + file->private_data = NULL; + if (state->req.reply_expected && !state->req.got_reply) + if (adb_wait_reply(state, file)) + return; + kfree(state); + } + return; +} + +static int adb_lseek(struct inode *inode, struct file *file, + off_t offset, int origin) +{ + return -ESPIPE; +} + +static int adb_read(struct inode *inode, struct file *file, + char *buf, int count) +{ + int ret; + struct adbdev_state *state = file->private_data; + + if (count < 2) + return -EINVAL; + if (count > sizeof(state->req.reply)) + count = sizeof(state->req.reply); + ret = verify_area(VERIFY_WRITE, buf, count); + if (ret) + return ret; + + if (!state->req.reply_expected) + return 0; + + ret = adb_wait_reply(state, file); + if (ret) + return ret; + + state->req.reply_expected = 0; + ret = state->req.reply_len; + copy_to_user(buf, state->req.reply, ret); + + return ret; +} + +static int adb_write(struct inode *inode, struct file *file, + const char *buf, int count) +{ + int ret, i; + struct adbdev_state *state = file->private_data; + + if (count < 2 || count > sizeof(state->req.data)) + return -EINVAL; + ret = verify_area(VERIFY_READ, buf, count); + if (ret) + return ret; + + if (state->req.reply_expected && !state->req.got_reply) { + /* A previous request is still being processed. + Wait for it to finish. */ + ret = adb_wait_reply(state, file); + if (ret) + return ret; + } + + state->req.nbytes = count; + state->req.done = adb_write_done; + state->req.got_reply = 0; + copy_from_user(state->req.data, buf, count); +#if 0 + switch (adb_hardware) { + case ADB_NONE: + return -ENXIO; + case ADB_VIACUDA: + state->req.reply_expected = 1; + cuda_send_request(&state->req); + break; + default: +#endif + if (state->req.data[0] != ADB_PACKET) + return -EINVAL; + for (i = 1; i < state->req.nbytes; ++i) + state->req.data[i] = state->req.data[i+1]; + state->req.reply_expected = + ((state->req.data[0] & 0xc) == 0xc); + adb_send_request(&state->req); +#if 0 + break; + } +#endif + + return count; +} + +static struct file_operations adb_fops = { + adb_lseek, + adb_read, + adb_write, + NULL, /* no readdir */ + NULL, /* no poll yet */ + NULL, /* no ioctl yet */ + NULL, /* no mmap */ + adb_open, + adb_release +}; + +int adbdev_register(int subtype, struct file_operations *fops) +{ + if (subtype < 0 || subtype > 15) + return -EINVAL; + if (adb_cooked[subtype]) + return -EBUSY; + adb_cooked[subtype] = fops; + return 0; +} + +int adbdev_unregister(int subtype) +{ + if (subtype < 0 || subtype > 15) + return -EINVAL; + if (!adb_cooked[subtype]) + return -ENODEV; + adb_cooked[subtype] = NULL; + return 0; +} + +void adbdev_init() +{ + if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) + printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); +} + + +#if 0 /* old ADB device */ + +/* + * Here are the file operations we export for /dev/adb. + */ + +#define ADB_MINOR 140 /* /dev/adb is c 10 140 */ + +extern void adbdev_inits(void); + +struct adbdev_state { + struct adb_request req; +}; + +static struct wait_queue *adb_wait; + +static int adb_wait_reply(struct adbdev_state *state, struct file *file) +{ + int ret = 0; + struct wait_queue wait = { current, NULL }; + +#if (ADBDEBUG & ADBDEBUG_DEVICE) + printk("ADB request: wait_reply (blocking ... \n"); +#endif + + add_wait_queue(&adb_wait, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (!state->req.got_reply) { + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + current->state = TASK_RUNNING; + remove_wait_queue(&adb_wait, &wait); + + return ret; +} + +static void adb_write_done(struct adb_request *req) +{ + if (!req->got_reply) { + req->reply_len = 0; + req->got_reply = 1; + } + wake_up_interruptible(&adb_wait); +} + +static int adb_open(struct inode *inode, struct file *file) +{ + struct adbdev_state *state; + + state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL); + if (state == 0) + return -ENOMEM; + file->private_data = state; + state->req.reply_expected = 0; + return 0; +} + +static void adb_release(struct inode *inode, struct file *file) +{ + struct adbdev_state *state = file->private_data; + + if (state) { + file->private_data = NULL; + if (state->req.reply_expected && !state->req.got_reply) + if (adb_wait_reply(state, file)) + return; + kfree(state); + } + return; +} + +static int adb_lseek(struct inode *inode, struct file *file, + off_t offset, int origin) +{ + return -ESPIPE; +} + +static int adb_read(struct inode *inode, struct file *file, + char *buf, int count) +{ + int ret; + struct adbdev_state *state = file->private_data; + + if (count < 2) + return -EINVAL; + if (count > sizeof(state->req.reply)) + count = sizeof(state->req.reply); + ret = verify_area(VERIFY_WRITE, buf, count); + if (ret) + return ret; + + if (!state->req.reply_expected) + return 0; + + ret = adb_wait_reply(state, file); + if (ret) + return ret; + + ret = state->req.reply_len; + memcpy_tofs(buf, state->req.reply, ret); + state->req.reply_expected = 0; + + return ret; +} + +static int adb_write(struct inode *inode, struct file *file, + const char *buf, int count) +{ + int ret; + struct adbdev_state *state = file->private_data; + + if (count < 2 || count > sizeof(state->req.data)) + return -EINVAL; + ret = verify_area(VERIFY_READ, buf, count); + if (ret) + return ret; + + if (state->req.reply_expected && !state->req.got_reply) { + /* A previous request is still being processed. + Wait for it to finish. */ + ret = adb_wait_reply(state, file); + if (ret) + return ret; + } + + state->req.nbytes = count; + state->req.done = adb_write_done; + memcpy_fromfs(state->req.data, buf, count); + state->req.reply_expected = 1; + state->req.got_reply = 0; + adb_send_request(&state->req); + + return count; +} + +static struct file_operations adb_fops = { + adb_lseek, + adb_read, + adb_write, + NULL, /* no readdir */ + NULL, /* no select */ + NULL, /* no ioctl */ + NULL, /* no mmap */ + adb_open, + adb_release +}; + +static struct miscdevice adb_dev = { + ADB_MINOR, + "adb", + &adb_fops +}; + +void adbdev_init(void) +{ + misc_register(&adb_dev); +} + +#endif /* old ADB device */ diff -ur --new-file old/linux/arch/m68k/mac/bootparse.c new/linux/arch/m68k/mac/bootparse.c --- old/linux/arch/m68k/mac/bootparse.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mac/bootparse.c Fri Feb 13 01:30:13 1998 @@ -0,0 +1,121 @@ +#include +#include +#include +#include +#include +#include + +/* + * Booter vars + */ + +int boothowto; +int _boothowto; + +/* + * Called early to parse the environment (passed to us from the booter) + * into a bootinfo struct. Will die as soon as we have our own booter + */ + +#define atol(x) simple_strtoul(x,NULL,0) + +void parse_booter(char *env) +{ + char *name; + char *value; +#if 0 + while(0 && *env) +#else + while(*env) +#endif + { + name=env; + value=name; + while(*value!='='&&*value) + value++; + if(*value=='=') + *value++=0; + env=value; + while(*env) + env++; + env++; +#if 0 + if(strcmp(name,"VIDEO_ADDR")==0) + mac_mch.videoaddr=atol(value); + if(strcmp(name,"ROW_BYTES")==0) + mac_mch.videorow=atol(value); + if(strcmp(name,"SCREEN_DEPTH")==0) + mac_mch.videodepth=atol(value); + if(strcmp(name,"DIMENSIONS")==0) + mac_mch.dimensions=atol(value); +#endif + if(strcmp(name,"BOOTTIME")==0) + mac_bi_data.boottime=atol(value); + if(strcmp(name,"GMTBIAS")==0) + mac_bi_data.gmtbias=atol(value); + if(strcmp(name,"BOOTERVER")==0) + mac_bi_data.bootver=atol(value); + if(strcmp(name,"MACOS_VIDEO")==0) + mac_bi_data.videological=atol(value); + if(strcmp(name,"MACOS_SCC")==0) + mac_bi_data.sccbase=atol(value); + if(strcmp(name,"MACHINEID")==0) + mac_bi_data.id=atol(value); + if(strcmp(name,"MEMSIZE")==0) + mac_bi_data.memsize=atol(value); + if(strcmp(name,"SERIAL_MODEM_FLAGS")==0) + mac_bi_data.serialmf=atol(value); + if(strcmp(name,"SERIAL_MODEM_HSKICLK")==0) + mac_bi_data.serialhsk=atol(value); + if(strcmp(name,"SERIAL_MODEM_GPICLK")==0) + mac_bi_data.serialgpi=atol(value); + if(strcmp(name,"SERIAL_PRINT_FLAGS")==0) + mac_bi_data.printmf=atol(value); + if(strcmp(name,"SERIAL_PRINT_HSKICLK")==0) + mac_bi_data.printhsk=atol(value); + if(strcmp(name,"SERIAL_PRINT_GPICLK")==0) + mac_bi_data.printgpi=atol(value); + if(strcmp(name,"PROCESSOR")==0) + mac_bi_data.cpuid=atol(value); + if(strcmp(name,"ROMBASE")==0) + mac_bi_data.rombase=atol(value); + if(strcmp(name,"TIMEDBRA")==0) + mac_bi_data.timedbra=atol(value); + if(strcmp(name,"ADBDELAY")==0) + mac_bi_data.adbdelay=atol(value); + } +#if 0 /* XXX: TODO with m68k_mach_* */ + /* Fill in the base stuff */ + boot_info.machtype=MACH_MAC; + /* Read this from the macinfo we got ! */ +/* boot_info.cputype=CPU_68020|FPUB_68881;*/ +/* boot_info.memory[0].addr=0;*/ +/* boot_info.memory[0].size=((mac_bi_data.id>>7)&31)<<20;*/ + boot_info.num_memory=1; /* On a MacII */ + boot_info.ramdisk_size=0; /* For now */ + *boot_info.command_line=0; +#endif + } + + +void print_booter(char *env) +{ + char *name; + char *value; + while(*env) + { + name=env; + value=name; + while(*value!='='&&*value) + value++; + if(*value=='=') + *value++=0; + env=value; + while(*env) + env++; + env++; + printk("%s=%s\n", name,value); + } + } + + diff -ur --new-file old/linux/arch/m68k/mac/config.c new/linux/arch/m68k/mac/config.c --- old/linux/arch/m68k/mac/config.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mac/config.c Fri Feb 13 01:30:13 1998 @@ -0,0 +1,575 @@ +/* + * linux/arch/m68k/mac/config.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +/* + * Miscellaneous linux stuff + */ + +#include +#include +#include +#include +#include +#include +#include +/* keyb */ +#include +#include +/* keyb */ +#include + +#define BOOTINFO_COMPAT_1_0 +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "via6522.h" + +/* old bootinfo stuff */ + +struct mac_booter_data mac_bi_data = {0,}; +int mac_bisize = sizeof mac_bi_data; + +struct compat_bootinfo compat_boot_info ={0,}; +int compat_bisize = sizeof compat_boot_info; + +int compat_bi = 0; + +/* New bootinfo stuff */ + +extern int m68k_num_memory; +extern struct mem_info m68k_memory[NUM_MEMINFO]; + +extern struct mem_info m68k_ramdisk; + +extern char m68k_command_line[CL_SIZE]; + +void *mac_env; /* Loaded by the boot asm */ + +extern int mac_keyb_init(void); +extern int mac_kbdrate(struct kbd_repeat *k); +extern void mac_kbd_leds(unsigned int leds); + +extern void (*kd_mksound)(unsigned int, unsigned int); +extern void mac_mksound(unsigned int, unsigned int); +extern int mac_floppy_init(void); +extern void mac_floppy_setup(char *,int *); + +extern void mac_gettod (int *, int *, int *, int *, int *, int *); + +extern void nubus_sweep_video(void); +extern void via_init_clock(void (*func)(int, void *, struct pt_regs *)); +extern void mac_debugging_long(int, long); + +/* Mac specific debug functions (in debug.c) */ +extern void mac_debug_init(void); + +#ifdef CONFIG_MAGIC_SYSRQ +static char mac_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000\000\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000\000\000\000-\000\000\000+\000"/* 0x40 - 0x4f */ + "\000\000\000\177\000\000\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\000\000\000()/*789456123" /* 0x60 - 0x6f */ + "0.\r\000\000\000\000\000\000\000\000\000\000\000\000\000"; /* 0x70 - 0x7f */ +#endif + +extern void (*kd_mksound)(unsigned int, unsigned int); + +void mac_get_model(char *str) +{ + strcpy(str,"Macintosh"); +} + +void mac_bang(int irq, void *vector, struct pt_regs *p) +{ + printk("Resetting ...\n"); + mac_reset(); +} + +void mac_sched_init(void (*vector)(int, void *, struct pt_regs *)) +{ + via_init_clock(vector); +} + +unsigned long mac_gettimeoffset (void) +{ + return 0L; +} + +extern int console_loglevel; + +void mac_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ + unsigned long time; + int leap, oldleap, isleap; + int mon_days[14] = { -1, 31, 27, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 }; + + time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */ + +#if 0 + printk("mac_gettod: boottime 0x%lx gmtbias %ld \n", + mac_bi_data.boottime, mac_bi_data.gmtbias); +#endif + + *minp = time / 60; + *secp = time - (*minp * 60); + time = *minp; /* minutes now */ + + *hourp = time / 60; + *minp = time - (*hourp * 60); + time = *hourp; /* hours now */ + + *dayp = time / 24; + *hourp = time - (*dayp * 24); + time = *dayp; /* days now ... */ + + /* for leap day calculation */ + *yearp = (time / 365) + 1970; /* approx. year */ + + /* leap year calculation - there's an easier way, I bet */ + /* calculate leap days up to previous year */ + oldleap = (*yearp-1)/4 - (*yearp-1)/100 + (*yearp-1)/400; + /* calculate leap days incl. this year */ + leap = *yearp/4 - *yearp/100 + *yearp/400; + /* this year a leap year ?? */ + isleap = (leap != oldleap); + + /* adjust days: days, excluding past leap days since epoch */ + time -= oldleap - (1970/4 - 1970/100 + 1970/400); + + /* precise year, and day in year */ + *yearp = (time / 365); /* #years since epoch */ + *dayp = time - (*yearp * 365) + 1; /* #days this year (0: Jan 1) */ + *yearp += 70; /* add epoch :-) */ + time = *dayp; + + if (isleap) /* add leap day ?? */ + mon_days[2] = 28; + + /* count the months */ + for (*monp = 1; time > mon_days[*monp]; (*monp)++) + time -= mon_days[*monp]; + + *dayp = time; + +#if 1 + printk("mac_gettod: %d-%d-%d %d:%d.%d GMT (GMT offset %d)\n", + *yearp, *monp, *dayp, *hourp, *minp, *secp, + (signed long) mac_bi_data.gmtbias); +#endif + + return; +} + +void mac_waitbut (void) +{ + ; +} + +extern struct consw fb_con; +extern struct fb_info *mac_fb_init(long *); +extern void mac_video_setup(char *, int *); + +void mac_debug_init (void) +{ + ; +} + +void (*mac_handlers[8])(int, void *, struct pt_regs *)= +{ + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler, + mac_default_handler +}; + + /* + * Parse a Macintosh-specific record in the bootinfo + */ + +__initfunc(int mac_parse_bootinfo(const struct bi_record *record)) +{ + int unknown = 0; + const u_long *data = record->data; + + if (compat_bi) + return(unknown); + + switch (record->tag) { + case BI_MAC_MODEL: + mac_bi_data.id = *data; + break; + case BI_MAC_VADDR: + mac_bi_data.videoaddr = *data; + break; + case BI_MAC_VDEPTH: + mac_bi_data.videodepth = *data; + break; + case BI_MAC_VROW: + mac_bi_data.videorow = *data; + break; + case BI_MAC_VDIM: + mac_bi_data.dimensions = *data; + break; + case BI_MAC_VLOGICAL: + mac_bi_data.videological = *data; + break; + case BI_MAC_SCCBASE: + mac_bi_data.sccbase = *data; + break; + case BI_MAC_BTIME: + mac_bi_data.boottime = *data; + break; + case BI_MAC_GMTBIAS: + mac_bi_data.gmtbias = *data; + break; + case BI_MAC_MEMSIZE: + mac_bi_data.memsize = *data; + break; + case BI_MAC_CPUID: + mac_bi_data.cpuid = *data; + break; + default: + unknown = 1; + } + return(unknown); +} + +__initfunc(void mac_copy_compat(void)) +{ + int i; + + compat_bi = 1; + + for (i=0; i NetBSD booter was used! */ + /* XXX FIXME: breaks for model > 31 */ + model=(mac_bi_data.cpuid>>2)&63; + printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); + } + + printk ("Detected Macintosh model: %d \n", model); + + while(m->ident != -1) + { + if(m->ident == model) + break; + m++; + } + if(m->ident==-1) + { + printk("\nUnknown macintosh model %d, probably unsupported.\n", + model); + mac_debugging_long(1, (long) 0x55555555); + mac_debugging_long(1, (long) model); + model = MAC_MODEL_Q800; + printk("Defaulting to: Quadra800, model id %d\n", model); + printk("Please report this case to linux-mac68k@wave.lm.com\n"); + m=&mac_data_table[0]; + while(m->ident != -1) + { + if(m->ident == model) + break; + m++; + } + if(m->ident==-1) + mac_boom(5); + } + + /* + * Report booter data: + */ + printk (" Penguin (bootinfo version %d) data:\n", 2-compat_bi); + printk (" Video: addr 0x%lx row 0x%lx depth %lx dimensions %d x %d\n", + mac_bi_data.videoaddr, mac_bi_data.videorow, + mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, + mac_bi_data.dimensions >> 16); + printk (" Boottime: 0x%lx GMTBias: 0x%lx \n", + mac_bi_data.boottime, mac_bi_data.gmtbias); + printk (" Videological 0x%lx, SCC at 0x%lx \n", + mac_bi_data.videological, mac_bi_data.sccbase); + printk (" Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", + mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); + printk ("Ramdisk: addr 0x%lx size 0x%lx\n", + m68k_ramdisk.addr, m68k_ramdisk.size); + + /* + * Save the pointer + */ + + macintosh_config=m; + + /* + * TODO: set the various fields in macintosh_config->hw_present here! + */ + +} + +void mac_report_hardware(void) +{ + printk("Apple Macintosh %s\n", macintosh_config->name); +} + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -ur --new-file old/linux/arch/m68k/mac/debug.c new/linux/arch/m68k/mac/debug.c --- old/linux/arch/m68k/mac/debug.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mac/debug.c Fri Feb 13 01:30:13 1998 @@ -0,0 +1,366 @@ +/* + * linux/arch/m68k/mac/debug.c + * + * Shamelessly stolen (SCC code and general framework) from: + * + * linux/arch/m68k/atari/debug.c + * + * Atari debugging and serial console stuff + * + * Assembled of parts of former atari/config.c 97-12-18 by Roman Hodek + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include + +#define BOOTINFO_COMPAT_1_0 +#include +#include +#include +#include + +extern char m68k_debug_device[]; + +extern struct compat_bootinfo compat_boot_info; + +extern unsigned long mac_videobase; +extern unsigned long mac_videodepth; +extern unsigned long mac_rowbytes; + +/* + * These two auxiliary debug functions should go away ASAP. Only usage: + * before the console output is up (after head.S come some other crucial + * setup routines :-) it permits writing 'data' to the screen as bit patterns + * (good luck reading those). Helped to figure that the bootinfo contained + * garbage data on the amount and size of memory chunks ... + * + * The 'pos' argument now simply means 'linefeed after print' ... + */ + +static int peng=0, line=0; + +void mac_debugging_short(int pos, short num) +{ + unsigned char *pengoffset; + unsigned char *pptr; + int i; + + if (!MACH_IS_MAC) { + /* printk("debug: %d !\n", num); */ + return; + } + + /* calculate current offset */ + pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes) + +80*peng; + + pptr=pengoffset; + + for(i=0;i<8*sizeof(short);i++) /* # of bits */ + { + /* value mask for bit i, reverse order */ + *pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00); + } + + peng++; + + if (pos) { + line++; + peng = 0; + } +} + +void mac_debugging_long(int pos, long addr) +{ + unsigned char *pengoffset; + unsigned char *pptr; + int i; + + if (!MACH_IS_MAC) { + /* printk("debug: #%ld !\n", addr); */ + return; + } + + pengoffset=(unsigned char *)(mac_videobase+(20+line*2)*mac_rowbytes) + +80*peng; + + pptr=pengoffset; + + for(i=0;i<8*sizeof(long);i++) /* # of bits */ + { + *pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00); + } + + peng++; + + if (pos) { + line++; + peng = 0; + } +} + +/* + * Penguin - used by head.S console; obsolete + */ +char that_penguin[]={ +#include "that_penguin.h" +}; + +/* + * B/W version of penguin, unfinished - any takers?? + */ +static char bw_penguin[]={ +#include "bw_penguin.h" +}; + +void mac_debugging_penguin(int peng) +{ + unsigned char *pengoffset; + unsigned char *pptr; + unsigned char *bwpdptr=bw_penguin; + int i; + + if (!MACH_IS_MAC) + return; + + if (compat_boot_info.bi_mac.videodepth ==1) + pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes) + +5*peng; + else + pengoffset=(unsigned char *)(mac_videobase+80*mac_rowbytes) + +20*peng; + + pptr=pengoffset; + + for(i=0;i<36;i++) + { + memcpy(pptr,bwpdptr,4); + bwpdptr+=4; + pptr+=mac_rowbytes; + } +} + +/* + * B/W version of flaming Mac, unfinished (see above). + */ +static char bw_kaboom_map[]={ +#include "bw_mac.h" +}; + +static void mac_boom_boom(void) +{ + static unsigned char *boomoffset=NULL; + unsigned char *pptr; + unsigned char *bwpdptr=bw_kaboom_map; + int i; + + if(!boomoffset) + if (compat_boot_info.bi_mac.videodepth == 1) { + boomoffset=(unsigned char *)(mac_videobase+160*mac_rowbytes); + } else { + boomoffset=(unsigned char *)(mac_videobase+256*mac_rowbytes); + } + else + if (compat_boot_info.bi_mac.videodepth == 1) + boomoffset+=5; + else + boomoffset+=32; + + pptr=boomoffset; + + for(i=0;i<36;i++) + { + memcpy(pptr,bwpdptr,4); + bwpdptr+=4; + pptr+=mac_rowbytes; + } +} + +void mac_boom(int booms) +{ + int i; + + if (!MACH_IS_MAC) + return; + + for(i=0;i 0; --i ) \ + MFPDELAY(); \ + } while(0) + +#ifndef CONFIG_SERIAL_CONSOLE +__initfunc(static void mac_init_scc_port( int cflag, int port )) +#else +void mac_init_scc_port( int cflag, int port ) +#endif +{ + extern int mac_SCC_reset_done; + static int clksrc_table[9] = + /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ + { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; + static int brgsrc_table[9] = + /* reg 14: 0 = RTxC, 2 = PCLK */ + { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; + static int clkmode_table[9] = + /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; + static int div_table[9] = + /* reg12 (BRG low) */ + { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; + + int baud = cflag & CBAUD; + int clksrc, clkmode, div, reg3, reg5; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* tables starts at 1200bps */ + + clksrc = clksrc_table[baud]; + clkmode = clkmode_table[baud]; + div = div_table[baud]; + + reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; + reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; + + (void)scc.cha_b_ctrl; /* reset reg pointer */ + SCC_WRITE( 9, 0xc0 ); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | + clkmode ); + SCC_WRITE( 3, reg3 ); + SCC_WRITE( 5, reg5 ); + SCC_WRITE( 9, 0 ); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE( 10, 0 ); /* NRZ mode */ + SCC_WRITE( 11, clksrc ); /* main clock source */ + SCC_WRITE( 12, div ); /* BRG value */ + SCC_WRITE( 13, 0 ); /* BRG high byte */ + SCC_WRITE( 14, brgsrc_table[baud] ); + SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); + SCC_WRITE( 3, reg3 | 1 ); + SCC_WRITE( 5, reg5 | 8 ); + + mac_SCC_reset_done = 1; + mac_SCC_init_done = 1; +} + + +__initfunc(void mac_debug_init(void)) +{ +#ifdef CONFIG_KGDB + /* the m68k_debug_device is used by the GDB stub, do nothing here */ + return; +#endif + if (!strcmp( m68k_debug_device, "ser" )) { + strcpy( m68k_debug_device, "ser1" ); + } + if (!strcmp( m68k_debug_device, "ser1" )) { + /* ST-MFP Modem1 serial port */ + mac_init_scc_port( B9600|CS8, 0 ); + mac_console_driver.write = mac_scc_console_write; + } + else if (!strcmp( m68k_debug_device, "ser2" )) { + /* SCC Modem2 serial port */ + mac_init_scc_port( B9600|CS8, 1 ); + mac_console_driver.write = mac_scc_console_write; + } + if (mac_console_driver.write) + register_console(&mac_console_driver); +} +#endif + +/* + * Local variables: + * c-indent-level: 4 + * tab-width: 8 + * End: + */ diff -ur --new-file old/linux/arch/m68k/mac/ksyms.c new/linux/arch/m68k/mac/ksyms.c --- old/linux/arch/m68k/mac/ksyms.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mac/ksyms.c Wed Mar 18 06:15:40 1998 @@ -0,0 +1,12 @@ +#include +#include +#include +#include +/* Hook for mouse driver */ +extern void (*mac_mouse_interrupt_hook) (char *); + +EXPORT_SYMBOL(mac_mouse_interrupt_hook); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif diff -ur --new-file old/linux/arch/m68k/mac/macboing.c new/linux/arch/m68k/mac/macboing.c --- old/linux/arch/m68k/mac/macboing.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mac/macboing.c Fri Feb 13 01:30:13 1998 @@ -0,0 +1,92 @@ +/* + * Mac bong noise generator. Note - we ought to put a boingy noise + * here 8) + */ + +#include +#include + +#include +#include + +static const signed char sine_data[] = { + 0, 39, 75, 103, 121, 127, 121, 103, 75, 39, + 0, -39, -75, -103, -121, -127, -121, -103, -75, -39 +}; +#define DATA_SIZE (sizeof(sine_data)/sizeof(sine_data[0])) + +static void nosound( unsigned long ignored ); +static struct timer_list sound_timer = { NULL, NULL, 0, 0, nosound }; + +static volatile unsigned char *asc_base=(void *)0x50F14000; + + +void mac_mksound( unsigned int hz, unsigned int ticks ) +{ + static int inited = 0; + unsigned long flags; + int samples=512; + + if(!inited) + { + int i=0; + int j=0; + int k=0; + int l=0; + for(i=0;i 20 && hz < 32767) { + int i; + u_long asc_pulses=((hz<<5)*samples)/468; + for(i=0;i<4;i++) + { + asc_base[ASC_FREQ(i,0)]=0x00; + asc_base[ASC_FREQ(i,1)]=20; + asc_base[ASC_FREQ(i,2)]=0x00; + asc_base[ASC_FREQ(i,3)]=20; + asc_base[ASC_FREQ(i,4)]=(asc_pulses>>24)&0xFF; + asc_base[ASC_FREQ(i,5)]=(asc_pulses>>16)&0xFF; + asc_base[ASC_FREQ(i,6)]=(asc_pulses>>8)&0xFF; + asc_base[ASC_FREQ(i,7)]=(asc_pulses>>0)&0xFF; + } + asc_base[ASC_CHAN]=0x03; + asc_base[ASC_VOLUME]=128; + asc_base[ASC_MODE]=ASC_MODE_SAMPLE; + asc_base[ASC_ENABLE]=ASC_ENABLE_SAMPLE; + if (ticks) { + sound_timer.expires = jiffies + ticks; + add_timer( &sound_timer ); + } + } else { + nosound( 0 ); + } + restore_flags(flags); +} + + +static void nosound( unsigned long ignored ) +{ + asc_base[ASC_ENABLE]=0; +} diff -ur --new-file old/linux/arch/m68k/mac/macints.c new/linux/arch/m68k/mac/macints.c --- old/linux/arch/m68k/mac/macints.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mac/macints.c Fri Feb 13 01:30:13 1998 @@ -0,0 +1,979 @@ +/* + * Macintosh interrupts + * + * General design: + * In contrary to the Amiga and Atari platforms, the Mac hardware seems to + * exclusively use the autovector interrupts (the 'generic level0-level7' + * interrupts with exception vectors 0x19-0x1f). The following interrupt levels + * are used: + * 1 - VIA1 + * - slot 0: one second interrupt + * - slot 1: VBlank + * - slot 2: ADB data ready (SR full) + * - slot 3: ADB data (CB2) + * - slot 4: ADB clock (CB1) + * - slot 5: timer 2 + * - slot 6: timer 1 + * - slot 7: status of IRQ; signals 'any enabled int.' + * + * 2 - VIA2, RBV or OSS + * - slot 0: SCSI DRQ + * - slot 1: NUBUS IRQ + * - slot 3: SCSI IRQ + * + * 4 - SCC + * - subdivided into Channel B and Channel A interrupts + * + * 6 - Off switch (??) + * + * 7 - Debug output + * + * Using the autovector irq numbers for Linux/m68k hardware interrupts without + * the IRQ_MACHSPEC bit set would interfere with the general m68k interrupt + * handling in kernel versions 2.0.x, so the following strategy is used: + * + * - mac_init_IRQ installs the low-level entry points for the via1 and via2 + * exception vectors and the corresponding handlers (C functions); these + * entry points just add the machspec bit and call the handlers proper. + * (in principle, the C functions can be installed as the exception vectors + * directly, as they are hardcoded anyway; that's the current method). + * + * - via[12]_irq determine what interrupt sources have triggered the interrupt, + * and call the corresponding device interrupt handlers. + * (currently, via1_irq and via2_irq just call via_irq, passing the via base + * address. RBV interrupts are handled by (you guessed it) rbv_irq). + * Some interrupt functions want to have the interrupt number passed, so + * via_irq and rbv_irq need to generate the 'fake' numbers from scratch. + * + * - for the request/free/enable/disable business, interrupt sources are + * numbered internally (suggestion: keep irq 0-7 unused :-). One bit in the + * irq number specifies the via# to use, i.e. via1 interrupts are 8-16, + * via2 interrupts 17-32, rbv interrupts ... + * The device interrupt table and the irq_enable bitmap is maintained by + * the machspec interrupt code; all device drivers should only use these + * functions ! + * + * - For future porting to version 2.1 (and removing of the machspec bit) it + * should be sufficient to use the same numbers (everything > 7 is assumed + * to be machspec, according to Jes!). + * + */ + +#include +#include +#include +#include +#include /* for intr_count */ + +#include +#include +#include +#include +#include +#include "via6522.h" + +#include + +/* + * Interrupt handler and parameter types + */ +struct irqhandler { + void (*handler)(int, void *, struct pt_regs *); + void *dev_id; +}; + +struct irqparam { + unsigned long flags; + const char *devname; +}; + +struct irqflags { + unsigned int disabled; + unsigned int pending; +}; + +/* + * Array with irq's and their parameter data. + */ +static struct irqhandler via1_handler[8]; +static struct irqhandler via2_handler[8]; +static struct irqhandler rbv_handler[8]; +static struct irqhandler scc_handler[8]; +static struct irqhandler nubus_handler[8]; + +static struct irqhandler *handler_table[8]; + +/* + * This array hold the rest of parameters of int handlers: type + * (slow,fast,prio) and the name of the handler. These values are only + * accessed from C + */ +static struct irqparam via1_param[8]; +static struct irqparam via2_param[8]; +static struct irqparam rbv_param[8]; +static struct irqparam scc_param[8]; +static struct irqparam nubus_param[8]; + +static struct irqparam *param_table[8]; + +/* + * This array holds the 'disabled' and 'pending' software flags maintained + * by mac_{enable,disable}_irq and the generic via_irq function. + */ + +static struct irqflags irq_flags[8]; + +/* + * This array holds the pointers to the various VIA or other interrupt + * controllers + */ + +static volatile unsigned char *via_table[8]; + +#ifdef VIABASE_WEIRDNESS +/* + * VIA2 / RBV default base address + */ + +volatile unsigned char *via2_regp = ((volatile unsigned char *)VIA2_BAS); +volatile unsigned char *rbv_regp = ((volatile unsigned char *)VIA2_BAS_IIci); +#endif + +/* + * Flags to control via2 / rbv behaviour + */ + +static int via2_is_rbv = 0; +static int rbv_clear = 0; + +/* + * console_loglevel determines NMI handler function + */ + +extern int console_loglevel; + +/* + * ADB test hooks + */ +extern int in_keybinit; +void adb_queue_poll(void); + +/* Defined in entry.S; only increments 'num_spurious' */ +asmlinkage void bad_interrupt(void); + +void nubus_wtf(int slot, void *via, struct pt_regs *regs); + +void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *regs); +void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs); + +static void via_do_nubus(int slot, void *via, struct pt_regs *regs); + +/*#define DEBUG_VIA*/ + +void mac_init_IRQ(void) +{ + int i; + + mac_debugging_penguin(6); + +#ifdef DEBUG_MACINTS + printk("Mac interrupt stuff initializing ...\n"); +#endif + /* initialize the hardwired (primary, autovector) IRQs */ + + /* level 1 IRQ: VIA1, always present */ + sys_request_irq(1, via1_irq, IRQ_FLG_LOCK, "via1", via1_irq); + + /* via2 or rbv?? */ + if (macintosh_config->via_type == MAC_VIA_IIci) { + /* VIA2 is part of the RBV: different base, other offsets */ + via2_is_rbv = 1; + /* LC III weirdness: IFR seems to behave like VIA2 */ + /* FIXME: maybe also for LC II ?? */ + if (macintosh_config->ident == MAC_MODEL_LCIII) { + rbv_clear = 0x0; + } else { + rbv_clear = 0x80; + } + /* level 2 IRQ: RBV/OSS; we only care about RBV for now */ + sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq); + } else + /* level 2 IRQ: VIA2 */ + sys_request_irq(2, via2_irq, IRQ_FLG_LOCK, "via2", via2_irq); + + /* + * level 4 IRQ: SCC - use 'master' interrupt routine that calls the + * registered channel-specific interrupts in turn. + * Currently, one interrupt per channel is used, solely + * to pass the correct async_info as parameter! + */ +#if 0 /* doesn't seem to work yet */ + sys_request_irq(4, mac_SCC_handler, IRQ_FLG_STD, "INT4", mac_SCC_handler); +#else + sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler); +#endif + /* Alan uses IRQ 5 for SCC ?? */ + sys_request_irq(5, mac_debug_handler, IRQ_FLG_STD, "INT5", mac_debug_handler); + + /* level 6 */ + sys_request_irq(6, mac_bang, IRQ_FLG_LOCK, "offswitch", mac_bang); + + /* level 7 (or NMI) : debug stuff */ + sys_request_irq(7, mac_nmi_handler, IRQ_FLG_STD, "NMI", mac_nmi_handler); + + /* initialize the handler tables for VIAs */ + for (i = 0; i < 8; i++) { + via1_handler[i].handler = mac_default_handler; + via1_handler[i].dev_id = NULL; + via1_param[i].flags = IRQ_FLG_STD; + via1_param[i].devname = NULL; + + via2_handler[i].handler = mac_default_handler; + via2_handler[i].dev_id = NULL; + via2_param[i].flags = IRQ_FLG_STD; + via2_param[i].devname = NULL; + + rbv_handler[i].handler = mac_default_handler; + rbv_handler[i].dev_id = NULL; + rbv_param[i].flags = IRQ_FLG_STD; + rbv_param[i].devname = NULL; + + scc_handler[i].handler = mac_default_handler; + scc_handler[i].dev_id = NULL; + scc_param[i].flags = IRQ_FLG_STD; + scc_param[i].devname = NULL; + + /* NUBUS interrupts routed through VIA2 slot 2 - special */ + nubus_handler[i].handler = nubus_wtf; + nubus_handler[i].dev_id = NULL; + nubus_param[i].flags = IRQ_FLG_STD; + nubus_param[i].devname = NULL; + + } + + /* initialize the handler tables (level 1 -> via_handler[0] !!!) */ + via_table[0] = via1_regp; + handler_table[0] = &via1_handler[0]; + param_table[0] = &via1_param[0]; + + if (via2_is_rbv) { + via_table[1] = rbv_regp; + handler_table[1] = &rbv_handler[0]; + param_table[1] = &rbv_param[0]; + } else { + via_table[1] = via2_regp; + handler_table[1] = &via2_handler[0]; + param_table[1] = &via2_param[0]; + } + via_table[2] = NULL; + via_table[3] = NULL; + + handler_table[2] = &rbv_handler[0]; + handler_table[3] = &nubus_handler[0]; + + param_table[2] = &rbv_param[0]; + param_table[3] = &nubus_param[0]; + + mac_debugging_penguin(7); +#ifdef DEBUG_MACINTS + printk("Mac interrupt init done!\n"); +#endif +} + +/* + * We have no machine specific interrupts on a macintoy + * Yet, we need to register/unregister interrupts ... :-) + * Currently unimplemented: Test for valid irq number, chained irqs, + * Nubus interrupts. + */ + +int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + struct irqhandler *via_handler; + struct irqparam *via_param; + volatile unsigned char *via; + +#ifdef DEBUG_MACINTS + printk ("%s: IRQ %d on VIA%d[%d] requested from %s\n", + __FUNCTION__, irq, srcidx+1, irqidx, devname); +#endif + + if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) { + printk ("%s: Bad irq type %ld requested from %s\n", + __FUNCTION__, flags, devname); + return -EINVAL; + } + + /* figure out what VIA is handling this irq */ + if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) { + /* non-via irqs unimplemented */ + printk ("%s: Bad irq source %d on VIA %d requested from %s\n", + __FUNCTION__, irq, srcidx, devname); + return -EINVAL; + } + + /* figure out if SCC pseudo-irq */ + if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) { + /* set specific SCC handler */ + scc_handler[irqidx].handler = handler; + scc_handler[irqidx].dev_id = dev_id; + scc_param[irqidx].flags = flags; + scc_param[irqidx].devname = devname; + /* and done! */ + return 0; + } + + via = (volatile unsigned char *) via_table[srcidx]; + if (!via) + return -EINVAL; + + via_handler = handler_table[srcidx]; + via_param = param_table[srcidx]; + + /* check for conflicts or possible replacement */ + + /* set the handler - no chained irqs yet !! */ + via_handler[irqidx].handler = handler; + via_handler[irqidx].dev_id = dev_id; + via_param[irqidx].flags = flags; + via_param[irqidx].devname = devname; + + /* and turn it on ... */ + if (srcidx == SRC_VIA2 && via2_is_rbv) + via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); + else + via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx))); + + + if (irq == IRQ_IDX(IRQ_MAC_SCSI)) { + /* + * Set vPCR for SCSI interrupts. (what about RBV here?) + */ + via_write(via, vPCR, 0x66); + } + + return 0; +} + +void mac_free_irq (unsigned int irq, void *dev_id) +{ + unsigned long flags; + int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + struct irqhandler *via_handler; + struct irqparam *via_param; + volatile unsigned char *via; + +#ifdef DEBUG_MACINTS + printk ("%s: IRQ %d on VIA%d[%d] freed\n", + __FUNCTION__, irq, srcidx+1, irqidx); +#endif + + /* figure out what VIA is handling this irq */ + if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) { + /* non-via irqs unimplemented */ + return; + } + + save_flags(flags); + cli(); + + /* figure out if SCC pseudo-irq */ + if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_NUBUS_1)) { + /* clear specific SCC handler */ + scc_handler[irqidx].handler = mac_default_handler; + scc_handler[irqidx].dev_id = NULL; + scc_param[irqidx].flags = IRQ_FLG_STD; + scc_param[irqidx].devname = NULL; + /* and done! */ + restore_flags(flags); + return; + } + + via = (volatile unsigned char *) via_table[srcidx]; + via_handler = handler_table[srcidx]; + via_param = param_table[srcidx]; + + if ( !via || (via_handler[irqidx].dev_id != dev_id) ) { + restore_flags(flags); + goto not_found; + } + + /* clear the handler - no chained irqs yet !! */ + via_handler[irqidx].handler = mac_default_handler; + via_handler[irqidx].dev_id = NULL; + via_param[irqidx].flags = IRQ_FLG_STD; + via_param[irqidx].devname = NULL; + + /* and turn it off */ + if (srcidx == SRC_VIA2 && via2_is_rbv) + via_write(via, rIER, (via_read(via, rIER)&(1<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + + irq_flags[srcidx].disabled &= ~(1<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + + irq_flags[srcidx].disabled |= (1<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + volatile unsigned char *via; + + via = (volatile unsigned char *) via_table[srcidx]; + if (!via) + return; + + if (srcidx == SRC_VIA2 && via2_is_rbv) + via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx))); + else + via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx))); + +} + +void mac_turnoff_irq( unsigned int irq ) +{ + int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + volatile unsigned char *via; + + via = (volatile unsigned char *) via_table[srcidx]; + if (!via) + return; + + if (srcidx == SRC_VIA2 && via2_is_rbv) + via_write(via, rIER, (via_read(via, rIER)&(1<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + + irq_flags[srcidx].pending &= ~(1<>3) - 1; + int irqidx = (irq & IRQ_IDX_MASK); + + return (irq_flags[srcidx].pending & (1<= 8 ) { +#if 0 + show_state(); + printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp); + printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", + fp->d0, fp->d1, fp->d2, fp->d3); + printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", + fp->d4, fp->d5, fp->a0, fp->a1); + + if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page) + printk("Corrupted stack page\n"); + printk("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, current->kernel_stack_page); + if (intr_count == 1) + dump_stack((struct frame *)fp); +#else + /* printk("NMI "); */ +#endif + } +} + +/* + * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's + * via6522.c :-), disable/pending masks added. + * The int *viaidx etc. is just to keep the prototype happy ... + */ + +static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs) +{ + unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F; + int i; + int ct = 0; + struct irqhandler *via_handler = handler_table[*viaidx]; + struct irqparam *via_param = param_table[*viaidx]; + + /* to be changed, possibly: for each non'masked', enabled IRQ, read + * flag bit, ack and call handler ... + * Currently: all pending irqs ack'ed en bloc. + * If ack for masked IRQ required: keep 'pending' info separate. + */ + + /* shouldn't we disable interrupts here ?? */ + + + /* + * Shouldnt happen + */ + + if(events==0) + { + printk("via_irq: nothing pending!\n"); + return; + } + +#ifdef DEBUG_VIA + /* + * limited verbosity for VIA interrupts + */ +#if 0 + if ( (*viaidx == 0 && events != 1<<6) /* timer int */ + || (*viaidx == 1 && events != 1<<3) ) /* SCSI IRQ */ +#else + if ( *viaidx == 0 && (events & 1<<2) ) +#endif + printk("via_irq: irq %d events %x !\n", (*viaidx)+1, events); +#endif + + do { + /* + * Clear the pending flag + */ + + via_write(via, vIFR, events); + + /* + * Now see what bits are raised + */ + + for(i=0;i<7;i++) + { + /* determine machspec. irq no. */ + int irq = ((*viaidx)+1)* 8 + i; + /* call corresponding handlers */ + if (events&(1< mark pending */ + irq_flags[*viaidx].pending |= (1< call handler */ + (via_handler[i].handler)(irq, via, regs); + } + } + /* and call handlers for pending irqs - first ?? */ + if ( (irq_flags[*viaidx].pending & (1<8) + { + printk("via%d: stuck events %x\n", (*viaidx)+1, events); + break; + } + } + while(events); +#if 0 + scsi_mac_polled(); +#endif +} + +/* + * Caution: the following stuff is called from process_int as _autovector_ + * system interrupts. So irq is always in the range 0-7 :-( and the selection + * of the appropriate VIA is up to the irq handler here based on the autovec + * irq number. There's no information whatsoever about which source on the VIA + * triggered the int - and that's what the machspec irq no's are about. + * Broken design :-(((( + */ + +/* + * System interrupts + */ + +void via1_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int srcidx = IRQ_IDX(irq) - 1; + via_irq((unsigned char *)via1_regp, &srcidx, regs); +} + + +/* + * Nubus / SCSI interrupts, VIA style (could be wrapped into via1_irq or + * via_irq directly by selecting the regp based on the irq!) + */ + +void via2_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int srcidx = IRQ_IDX(irq) - 1; + via_irq((unsigned char *)via2_regp, &srcidx, regs); +} + +/* + * Nubus / SCSI interrupts; RBV style + * The RBV is different. RBV appears to stand for randomly broken + * VIA (or even real broken VIA). + */ + +void rbv_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + int srcidx = IRQ_IDX(irq) - 1; /* MUST be 1 !! */ + volatile unsigned char *via = rbv_regp; + unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F; + int i; + int ct = 0; + struct irqhandler *via_handler = handler_table[srcidx]; + struct irqparam *via_param = param_table[srcidx]; + +#ifdef DEBUG_VIA + /* + * limited verbosity for RBV interrupts (add more if needed) + */ + if ( srcidx == 1 && events != 1<<3 ) /* SCSI IRQ */ + printk("rbv_irq: irq %d (%d) events %x !\n", irq, srcidx+1, events); +#endif + + /* to be changed, possibly: for each non'masked', enabled IRQ, read + * flag bit, ack and call handler ... + * Currently: all pending irqs ack'ed en bloc. + * If ack for masked IRQ required: keep 'pending' info separate. + */ + + /* shouldn't we disable interrupts here ?? */ + + + /* + * Shouldnt happen + */ + + if(events==0) + { + printk("rbv_irq: nothing pending!\n"); + return; + } + + do { + /* + * Clear the pending flag + */ + + via_write(via, rIFR, events | rbv_clear); + + /* + * Now see what bits are raised + */ + + for(i=0;i<7;i++) + { + /* determine machspec. irq no. */ + int irq = (srcidx+1)* 8 + i; + /* call corresponding handlers */ + if (events&(1< mark pending */ + irq_flags[srcidx].pending |= (1< call handler */ + (via_handler[i].handler)(irq, via, regs); + } + /* and call handlers for pending irqs - first ?? */ + if ( (irq_flags[srcidx].pending & (1<8) + { + printk("rbv: stuck events %x\n",events); + for(i=0;i<7;i++) + { + if(events&(1<2) + { + printk("nubus stuck events - %d/%d\n", map, nubus_active); + return; + } + + for(i=0;i<7;i++) + { + if(map&(1< +#include +#include +#include +#include +#include +/* keyb */ +#include +#include +#include +/* keyb */ + +#include + +#include +#include +#include +#include +#include + +#include +#include +/* for keyboard_input stuff */ +#include +#define KEYB_KEYREG 0 /* register # for key up/down data */ +#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ +#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ +/* end keyboard_input stuff */ + +#include +#include +#include + +static void kbd_repeat(unsigned long); +static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; +static int last_keycode; + +static void input_keycode(int, int); + +extern struct kbd_struct kbd_table[]; + +extern void handle_scancode(unsigned char); +extern void put_queue(int); + +/* keyb */ +static void mac_leds_done(struct adb_request *); +static void keyboard_input(unsigned char *, int, struct pt_regs *); +static void mouse_input(unsigned char *, int, struct pt_regs *); +/* Hook for mouse driver */ +void (*mac_mouse_interrupt_hook) (char *); +int mac_emulate_button2; +int mac_emulate_button3; +/* The mouse driver - for debugging */ +extern void mac_mouse_interrupt(char *); +/* end keyb */ + +/* 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, +}; + +/* + * Mac private key maps + */ +u_short mac_plain_map[NR_KEYS] = { + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, + 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, + 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, + 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, + 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, + 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xfb61, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_shift_map[NR_KEYS] = { + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, + 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, + 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, + 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, + 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, + 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xfb41, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, + 0xf10b, 0xf20a, 0xf10a, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_altgr_map[NR_KEYS] = { + 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, + 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, + 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, + 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, + 0xf910, 0xf911, 0xf914, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, + 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, + 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, + 0xf50d, 0xf119, 0xf50c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, + 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, + 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, + 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, + 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_shift_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, + 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, + 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf001, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, + 0xf200, 0xf119, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf20c, +}; + +u_short mac_alt_map[NR_KEYS] = { + 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, + 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, + 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, + 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, + 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, + 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, + 0xf906, 0xf907, 0xf861, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +u_short mac_ctrl_alt_map[NR_KEYS] = { + 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, + 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, + 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, + 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf801, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +extern unsigned int keymap_count; + +#if 0 +ushort *mac_key_maps[MAX_NR_KEYMAPS] = { + mac_plain_map, mac_shift_map, mac_altgr_map, 0, + mac_ctrl_map, mac_shift_ctrl_map, 0, 0, + mac_alt_map, 0, 0, 0, + mac_ctrl_alt_map, 0 +}; +#endif + +/* + * Misc. defines for testing + */ + +extern int console_loglevel; + +static struct adb_request led_request; +extern int in_keybinit; + +/* + * machdep keyboard routines, interface and key repeat method modeled after + * drivers/macintosh/keyb_mac.c + */ + +int mac_kbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode) +{ + if (!raw_mode) { + /* + * Convert R-shift/control/option to L version. + * Remap keycode 0 (A) to the unused keycode 0x5a. + * Other parts of the system assume 0 is not a valid keycode. + */ + switch (keycode) { + case 0x7b: keycode = 0x38; break; /* R-shift */ + case 0x7c: keycode = 0x3a; break; /* R-option */ + case 0x7d: keycode = 0x36; break; /* R-control */ + case 0: keycode = 0x5a; break; /* A */ + } + } + *keycodep = keycode; + return 1; +} + +int mac_kbd_unexpected_up(unsigned char keycode) +{ + return 0x80; +} + +static void +keyboard_input(unsigned char *data, int nb, struct pt_regs *regs) +{ + /* first check this is from register 0 */ + if (nb != 5 || (data[2] & 3) != KEYB_KEYREG) + return; /* ignore it */ + kbd_pt_regs = regs; + input_keycode(data[3], 0); + if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f))) + input_keycode(data[4], 0); +} + +static void +input_keycode(int keycode, int repeat) +{ + struct kbd_struct *kbd; + int up_flag; + + kbd = kbd_table + fg_console; + up_flag = (keycode & 0x80); + keycode &= 0x7f; + if (!repeat) + del_timer(&repeat_timer); + + /* + * XXX: Add mouse button 2+3 fake codes here if mouse open. + * As we only report up/down events, keep track of faked buttons. + * Really messy; might need to check if keyboard is in + * VC_RAW mode for X?. + * Might also want to know how many buttons need to be emulated. + * -> hide this as function in arch/m68k/mac ? + * Current emulation buttons: right alt/option and control + * (wanted: command and alt/option, or KP= and KP( ...) + * Debug version; might be rewritten to be faster on normal keys. + */ + if (mac_mouse_interrupt_hook || console_loglevel >= 8) { + unsigned char button, button2, button3, fake_event; + static unsigned char button2state=0, button3state=0; /* up */ + /* faked ADB packet: device type ff, handler 4 ! */ + static char data[6] = { 0xff, 0x40, 0x3c, 0x80, 0x80, 0x80 }; + + button = 0; + fake_event = 0; + switch (keycode) { /* which 'button' ? */ + case 0x7c: /* R-option */ + button2 = (!up_flag); /* new state */ + if (button2 != button2state) /* change ? */ + button = 2; + button2state = button2; /* save state */ + fake_event = 2; + break; + case 0x7d: /* R-control */ + button3 = (!up_flag); /* new state */ + if (button3 != button3state) /* change ? */ + button = 3; + button3state = button3; /* save state */ + fake_event = 3; + break; + } +#ifdef DEBUG_ADBMOUSE + if (fake_event && console_loglevel >= 8) + printk("fake event: button2 %d button3 %d button %d\n", + button2state, button3state, button); +#endif + if (button) { /* there's been a button state change */ + /* fake a mouse packet : send all bytes, change one! */ + data[button+2] = (up_flag ? 0x80 : 0); + if (mac_mouse_interrupt_hook) + mac_mouse_interrupt_hook(data); +#ifdef DEBUG_ADBMOUSE + else + printk("mouse_fake: data %2x %2x %2x buttons %2x \n", + data[3], data[4], data[5], + ~( (data[3] & 0x80 ? 0 : 4) + | (data[4] & 0x80 ? 0 : 1) + | (data[5] & 0x80 ? 0 : 2) )&7 ); +#endif + } + /* + * for mouse 3-button emulation: don't process 'fake' keys! + * Keys might autorepeat, and console state gets generally messed + * up enough so that selection stops working. + */ + if (fake_event) + return; + } + + /* + * Convert R-shift/control/option to L version. + */ + switch (keycode) { + case 0x7b: keycode = 0x38; break; /* R-shift */ + case 0x7c: keycode = 0x3a; break; /* R-option */ + case 0x7d: keycode = 0x36; break; /* R-control */ + case 0x0: if (kbd->kbdmode != VC_RAW) + keycode = 0x5a; /* A; keycode 0 deprecated */ + break; + } + + if (kbd->kbdmode != VC_RAW) { + if (!up_flag && !dont_repeat[keycode]) { + last_keycode = keycode; + repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2); + add_timer(&repeat_timer); + } + + /* + * XXX fix caps-lock behaviour by turning the key-up + * transition into a key-down transition. + * MSch: need to turn each caps-lock event into a down-up + * double event (keyboard code assumes caps-lock is a toggle) + */ +#if 0 + if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK)) + up_flag = 0; +#else + if (keycode == 0x39) { + handle_scancode(keycode); /* down */ + up_flag = 0x80; /* see below ... */ + } +#endif + } + + handle_scancode(keycode + up_flag); +} + +static void +kbd_repeat(unsigned long xxx) +{ + unsigned long flags; + + save_flags(flags); + cli(); + input_keycode(last_keycode, 1); + restore_flags(flags); +} + + /* [ACA:23-Mar-97] Three button mouse support. This is designed to + function with MkLinux DR-2.1 style X servers. It only works with + three-button mice that conform to Apple's multi-button mouse + protocol. */ + + /* + The X server for MkLinux DR2.1 uses the following unused keycodes to + read the mouse: + + 0x7e This indicates that the next two keycodes should be interpreted + as mouse information. The first following byte's high bit + represents the state of the left button. The lower seven bits + represent the x-axis acceleration. The lower seven bits of the + second byte represent y-axis acceleration. + + 0x3f The x server interprets this keycode as a middle button + release. + + 0xbf The x server interprets this keycode as a middle button + depress. + + 0x40 The x server interprets this keycode as a right button + release. + + 0xc0 The x server interprets this keycode as a right button + depress. + + NOTES: There should be a better way of handling mice in the X server. + The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead + of two. The three mouse buttons should then, in the X server, be read + as the high-bits of all three bytes. The x and y motions can still be + in the first two bytes. Maybe I'll do this... + */ + + /* + Handler 4 -- Apple Extended mouse protocol. + + For Apple's 3-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = 0000 0000 ADB packet identifer. + data[1] = 0100 0000 Extended protocol register. + Bits 6-7 are the device id, which should be 1. + Bits 4-5 are resolution which is in "units/inch". + The Logitech MouseMan returns these bits clear but it has + 200/300cpi resolution. + Bits 0-3 are unique vendor id. + data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device. + Bits 2-3 should be 8 + 4. + Bits 4-7 should be 3 for a mouse device. + data[3] = bxxx xxxx Left button and x-axis motion. + data[4] = byyy yyyy Second button and y-axis motion. + data[5] = byyy bxxx Third button and fourth button. Y is additional + high bits of y-axis motion. XY is additional + high bits of x-axis motion. + + NOTE: data[0] and data[2] are confirmed by the parent function and + need not be checked here. + */ + + /* + Handler 1 -- 100cpi original Apple mouse protocol. + Handler 2 -- 200cpi original Apple mouse protocol. + + For Apple's standard one-button mouse protocol the data array will + contain the following values: + + BITS COMMENTS + data[0] = 0000 0000 ADB packet identifer. + data[1] = ???? ???? (?) + data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device. + data[3] = bxxx xxxx First button and x-axis motion. + data[4] = byyy yyyy Second button and y-axis motion. + + NOTE: data[0] is confirmed by the parent function and need not be + checked here. + */ + +static void +mouse_input(unsigned char *data, int nb, struct pt_regs *regs) +{ + struct kbd_struct *kbd; + int i; + + if (nb < 5 || nb > 6 || (data[2] & 3) != MOUSE_DATAREG) { + printk("data from mouse:"); + for (i = 0; i < nb; ++i) + printk(" %x", data[i]); + printk("\n"); + return; + } + + if (mac_mouse_interrupt_hook) { + mac_mouse_interrupt_hook(data); + /* + * passing the mouse data to i.e. the X server as done for + * Xpmac will confuse applications on a sane X server :-) + */ + return; + } +#ifdef DEBUG_ADBMOUSE + else + if (console_loglevel >= 8) + printk("mouse_input: data %x %x %x buttons %x dx %d dy %d \n", + data[3], data[4], data[5], + ~((data[3] & 0x80 ? 0 : 4) + | (data[4] & 0x80 ? 0 : 1) + | (data[5] & 0x80 ? 0 : 2))&7, + ((data[4]&0x7f) < 64 ? (data[4]&0x7f) : (data[4]&0x7f)-128 ), + ((data[3]&0x7f) < 64 ? -(data[3]&0x7f) : 128-(data[3]&0x7f) ) ); +#endif + + + kbd = kbd_table + fg_console; + +#if 0 /* The entirely insane way of MkLinux handling mouse input */ + /* Requires put_queue which is static in keyboard.c :-( */ + /* Only send mouse codes when keyboard is in raw mode. */ + if (kbd->kbdmode == VC_RAW) { + static unsigned char uch_ButtonStateSecond = 0; + unsigned char uchButtonSecond; + + /* Send first button, second button and movement. */ + put_queue( 0x7e ); + put_queue( data[3] ); + put_queue( data[4] ); + + /* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */ + + /* Store the button state. */ + uchButtonSecond = (data[4] & 0x80); + + /* Send second button. */ + if (uchButtonSecond != uch_ButtonStateSecond) { + put_queue( 0x3f | uchButtonSecond ); + uch_ButtonStateSecond = uchButtonSecond; + } + + /* Macintosh 3-button mouse (handler 4). */ + if ((nb == 6) && (data[1] & 0x40)) { + static unsigned char uch_ButtonStateThird = 0; + unsigned char uchButtonThird; + + /* Store the button state for speed. */ + uchButtonThird = (data[5] & 0x80); + + /* Send third button. */ + if (uchButtonThird != uch_ButtonStateThird) { + put_queue( 0x40 | uchButtonThird ); + uch_ButtonStateThird = uchButtonThird; + } + } + } +#endif /* insane MkLinux mouse hack */ +} + +/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ +static unsigned char mac_ledmap[8] = { + 0, /* none */ + 4, /* scroll lock */ + 1, /* num lock */ + 5, /* scroll + num lock */ + 2, /* caps lock */ + 6, /* caps + scroll lock */ + 3, /* caps + num lock */ + 7, /* caps + num + scroll lock */ +}; + +static int leds_pending; + +void mac_kbd_leds(unsigned int leds) +{ + if (led_request.got_reply) { +#ifdef DEBUG_ADB + if (console_loglevel == 10) + printk("mac_kbd_leds: got reply, sending request!\n"); +#endif + adb_request(&led_request, mac_leds_done, 4, ADB_PACKET, + ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), + 0xff, ~mac_ledmap[leds]); + } else + leds_pending = leds | 0x100; +} + +static void mac_leds_done(struct adb_request *req) +{ + int leds; + + if (leds_pending) { + leds = leds_pending & 0xff; + leds_pending = 0; + mac_kbd_leds(leds); + } + mark_bh(KEYBOARD_BH); +} + +int mac_kbdrate(struct kbd_repeat *k) +{ + return 0; +} + +int mac_keyb_init(void) +{ + static struct adb_request autopoll_req, confcod_req, mouse_req, readkey_req; + volatile int ct; + + /* setup key map */ + key_maps[0] = mac_plain_map; + key_maps[1] = mac_shift_map; + key_maps[2] = mac_altgr_map; + key_maps[4] = mac_ctrl_map; + key_maps[5] = mac_shift_ctrl_map; + key_maps[8] = mac_alt_map; + /* key_maps[9] = atashift_alt_map; */ + key_maps[12] = mac_ctrl_alt_map; + /* key_maps[13] = atashift_ctrl_alt_map; */ + memcpy (plain_map, mac_plain_map, sizeof(plain_map)); + keymap_count = 7; + + /* initialize mouse interrupt hook */ + mac_mouse_interrupt_hook = NULL; + /* assume broken mouse :-) */ + mac_emulate_button2 = 1; + mac_emulate_button3 = 1; + + /* + * Might put that someplace else, possibly .... + */ + adb_bus_init(); + + /* the input functions ... */ + adb_register(ADB_KEYBOARD, keyboard_input); + adb_register(ADB_MOUSE, mouse_input); + + /* turn on ADB auto-polling in the CUDA */ + + /* + * Older boxes don't support CUDA_* targets and CUDA commands + * instead we emulate them in the adb_request hook to make + * the code interfaces saner. + * + * Note XXX: the Linux PMac and this code both assume the + * devices are at their primary ids and do not do device + * assignment. This isn't ideal. We should fix it to follow + * the reassignment specs. + */ + + if (macintosh_config->adb_type == MAC_ADB_CUDA) { + printk("CUDA autopoll on ...\n"); + adb_request(&autopoll_req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); + ct=0; + while (!autopoll_req.got_reply && ++ct<1000) + { + adb_poll(); + udelay(10); + } + if(ct==1000) + printk("Keyboard timed out.\n"); + } + + /* + * XXX: all ADB requests now in CUDA format; adb_request takes + * care of that for other Macs. + */ + + printk("Configuring keyboard\n"); + + /* + * turn on all leds - the keyboard driver will turn them back off + * via mac_kbd_leds if everything works ok! + */ + printk("leds on ...\n"); + adb_request(&led_request, NULL, 4, ADB_PACKET, + ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, ~7); + + /* + * The polling stuff should go away as soon as the ADB driver is stable + */ + ct = 0; + adb_poll(); + while (!led_request.got_reply && ++ct<1000) + { + adb_poll(); + udelay(10); + } + if(ct==1000) + printk("Keyboard timed out.\n"); + +#if 1 + printk("Configuring coding mode ...\n"); + + /* + * get the keyboard to send separate codes for + * left and right shift, control, option keys. + */ + adb_request(&confcod_req, NULL, 4, ADB_PACKET, + ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3); + + ct=0; + adb_poll(); + while (!confcod_req.got_reply && ++ct<1000) + { + adb_poll(); + udelay(10); + } + if(ct==1000) + printk("Keyboard timed out.\n"); +#endif + +#if 0 /* seems to hurt, at least Geert's Mac */ + printk("Configuring mouse (3-button mode) ...\n"); + + /* + * XXX: taken from the PPC driver again ... + * Try to switch the mouse (id 3) to handler 4, for three-button + * mode. (0x20 is Service Request Enable, 0x03 is Device ID). + */ + adb_request(&mouse_req, NULL, 4, ADB_PACKET, + ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 ); + + ct=0; + adb_poll(); + while (!mouse_req.got_reply && ++ct<1000) + { + adb_poll(); + udelay(10); + } + if(ct==1000) + printk("Mouse timed out.\n"); +#endif + +#if 0 + printk("Start polling keyboard ...\n"); + + /* + * get the keyboard to send data back, via the adb_input hook + * XXX: was never used properly, and the driver takes care + * of polling and timeout retransmits now. + * Might be of use if we want to start talking to a specific + * device here... + */ + adb_request(&readkey_req, NULL, 2, ADB_PACKET, + ADB_READREG(ADB_KEYBOARD, KEYB_KEYREG)); +#endif + + /* + * fake 'request done' for the driver if requests timed out + */ + + autopoll_req.got_reply = 1; +#if 0 + /* XXX: results in race and hang with mac_kbd_leds and serial (why ?) */ + led_request.got_reply = 1; +#endif + confcod_req.got_reply = 1; + + in_keybinit = 0; + printk("Keyboard init done\n"); + + return 0; +} diff -ur --new-file old/linux/arch/m68k/mac/via6522.c new/linux/arch/m68k/mac/via6522.c --- old/linux/arch/m68k/mac/via6522.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mac/via6522.c Sat Feb 21 03:28:21 1998 @@ -0,0 +1,590 @@ + +/* + * 6522 Versatile Interface Adapter (VIA) + * + * There are two of these on the Mac II. Some IRQ's are vectored + * via them as are assorted bits and bobs - eg rtc, adb. + */ + +#include +#include +#include + +#include +#include +#include "via6522.h" + +volatile unsigned char *via1=(unsigned char *)VIABASE; +volatile unsigned char *via2=(unsigned char *)VIABASE2; + +unsigned char via1_clock, via1_datab; + +static int rbv=0; + +/* + * Debugging the VBL ints + */ + +extern int console_loglevel; + +/* + * VIA1 - hardwired vectors + */ + +#if 0 /* gone to macints.[ch] */ +extern void via_wtf(int slot, void *via, struct pt_regs *regs); +static void via_do_nubus(int slot, volatile void *via, struct pt_regs *regs); + +extern void adb_interrupt(int slot, void *via, struct pt_regs *regs); + +static struct via_irq_tab via1_func_tab= +{ + { + via_wtf, /* One second interrupt */ + via_wtf, /* Vblank */ + via_wtf, /* ADB data ready */ + via_wtf, /* ADB data */ + via_wtf, /* ADB clock */ + via_wtf, + via_wtf, /* Slot 6 is replaced by the timer */ + via_wtf + } +}; + +static struct via_irq_tab via2_func_tab= +{ + { + via_wtf, + via_do_nubus, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf + } +}; + +static struct via_irq_tab nubus_func_tab= +{ + { + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf, + via_wtf + } +}; +#endif + +extern void adb_interrupt(int slot, void *via, struct pt_regs *regs); + +#define MAC_CLOCK_TICK (783300/HZ) /* ticks per HZ */ +#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) +#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) + + +void via_init_clock(void (*func)(int, void *, struct pt_regs *)) +{ + unsigned char c; + +/* mac_debugging_penguin(6);*/ + + switch(macintosh_config->via_type) + { + /* + * CI, SI, VX, LC + */ + case MAC_VIA_IIci: + via1=(void *)0x50F00000; + via2=(void *)0x50F26000; + rbv=1; + break; + /* + * Quadra and early MacIIs agree on the VIA locations + */ + case MAC_VIA_QUADRA: + case MAC_VIA_II: + via1=(void *)0x50F00000; + via2=(void *)0x50F02000; + break; + default: + } + via1_clock=via_read(via1, vACR); + via1_datab=via_read(via1, vBufB); + + /* + * Tell what MacOS left us with + */ + + printk("via_init: boot via1 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n", + (int)via1_clock, (int)via_read(via1, vPCR), + (int)via_read(via1, vBufA), (int)via_read(via1, vDirA), + (int)via_read(via1, vBufB), (int)via_read(via1, vDirB)); + + if (rbv == 0) + printk("via_init: boot via2 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n", + (int)via_read(via2, vACR), (int)via_read(via2, vPCR), + (int)via_read(via2, vBufA), (int)via_read(via2, vDirA), + (int)via_read(via2, vBufB), (int)via_read(via2, vDirB)); + + /* + * Shut it down + */ + + via_write(via1,vIER, 0x7F); + + /* + * Kill the timers + */ + + via_write(via1,vT1LL,0); + via_write(via1,vT1LH,0); + via_write(via1,vT1CL,0); + via_write(via1,vT1CH,0); + via_write(via1,vT2CL,0); + via_write(via1,vT2CH,0); + + /* + * Now do via2 + */ + + if(rbv==0) + { + via_write(via2,vT1LL,0); + via_write(via2,vT1LH,0); + via_write(via2,vT1CL,0); + via_write(via2,vT1CH,0); + via_write(via2,vT2CL,0); + via_write(via2,vT2CH,0); + via_write(via2,vIER, 0x7F); + } + else + { + /* + * Init the RBV chip a bit + */ + + via_write(via2, rIER,0x7F); + } + + /* + * Disable the timer latches + */ + + c=via_read(via1,vACR); + via_write(via1,vACR,c&0x3F); + + if(rbv==0) + { + c=via_read(via2,vACR); + via_write(via2,vACR,c&0x3F); + } + + /* + * Now start the clock - we want 100Hz + */ + + via_write(via1,vACR,via_read(via1,vACR)|0x40); + + via_write(via1,vT1LL, MAC_CLOCK_LOW); + via_write(via1,vT1LH, MAC_CLOCK_HIGH); + via_write(via1,vT1CL, MAC_CLOCK_LOW); + via_write(via1,vT1CH, MAC_CLOCK_HIGH); + + /* + * And enable its interrupt + */ + + request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func); + +/* mac_debugging_penguin(7);*/ + + /* + * SE/30: disable video int. + * XXX: testing for SE/30 VBL + */ + + if (macintosh_config->ident == MAC_MODEL_SE30 + && console_loglevel != 10) { + c = via_read(via1, vBufB); + via_write(via1, vBufB, c|(0x40)); + c = via_read(via1, vDirB); + via_write(via1, vDirB, c|(0x40)); + } + + /* + * XXX: use positive edge + */ + + if (console_loglevel == 10) { + c = via_read(via1, vPCR); + via_write(via1, vPCR, c|(0x1)); + } + +#if 0 /* gone to mac_init_IRQ */ + /* + * Set vPCR for SCSI interrupts. + * + * That is: CA1 negative edge int., CA2 indep., positive edge int.; + * CB1 negative edge int., CB2 indep., positive edge int.. + */ + via_write(via2,vPCR, 0x66); +#endif + +} + +#if 0 /* moved to macints.c */ + +static void via_irq(volatile unsigned char *via, struct via_irq_tab *irqtab, + struct pt_regs *regs) +{ + unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F; + int i; + int ct=0; + + /* + * Shouldnt happen + */ + + if(events==0) + { + printk("via_irq: nothing pending!\n"); + return; + } + + do { + /* + * Clear the pending flag + */ + + /* HACK HACK - FIXME !!! - just testing some keyboard ideas */ + + /* events&=~(1<<4); */ + via_write(via, vIFR, events); + + /* + * Now see what bits are raised + */ + + for(i=0;i<7;i++) + { + if(events&(1<vector[i])(i, via, regs); + } + + /* + * And done.. + */ + events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F; + ct++; + if(events && ct>8) + { + printk("via: stuck events %x\n",events); + break; + } + } + while(events); + + scsi_mac_polled(); +} + +/* + * + * The RBV is different. RBV appears to stand for randomly broken + * VIA. + */ + +static void rbv_irq(volatile unsigned char *via, struct via_irq_tab *irqtab, + struct pt_regs *regs) +{ + unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F; + int i; + int ct=0; + + /* + * Shouldnt happen + */ + + if(events==0) + { + printk("rbv_irq: nothing pending!\n"); + return; + } + + do { + /* + * Clear the pending flag + */ + + /* HACK HACK - FIXME !!! - just testing some keyboard ideas */ + + /* events&=~(1<<4); */ + via_write(via, rIFR, events); + + /* + * Now see what bits are raised + */ + + for(i=0;i<7;i++) + { + if(events&(1<vector[i])(i, via, regs); + } + + /* + * And done.. + */ + events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F; + ct++; + if(events && ct>8) + { + printk("rbv: stuck events %x\n",events); + for(i=0;i<7;i++) + { + if(events&(1<2) + { + printk("nubus stuck events - %d/%d\n", map, nubus_active); + return; + } + for(i=0;i<7;i++) + { + if(map&(1<mmap_sem); - /* Are we prepared to handle this fault? */ + /* User mode accesses just cause a SIGSEGV */ + if (user_mode(regs)) { + force_sig (SIGSEGV, tsk); + return 1; + } + + /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->pc)) != 0) { struct pt_regs *tregs; - printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", - current->comm, regs->pc, fixup); /* Create a new four word stack frame, discarding the old one. */ regs->stkadj = frame_extra_sizes[regs->format]; @@ -115,12 +119,6 @@ tregs->pc = fixup; tregs->sr = regs->sr; return -1; - } - - if (user_mode(regs)) { - /* User memory access */ - force_sig (SIGSEGV, tsk); - return 1; } /* 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 Jun 17 01:35:54 1997 +++ new/linux/arch/m68k/mm/init.c Fri Feb 13 01:30:13 1998 @@ -23,6 +23,9 @@ #include #include #include +#ifdef CONFIG_ATARI +#include +#endif extern void die_if_kernel(char *,struct pt_regs *,long); extern void init_kpointer_table(void); @@ -63,6 +66,7 @@ { unsigned long i; int free = 0, total = 0, reserved = 0, nonshared = 0, shared = 0; + int cached = 0; printk("\nMem-info:\n"); show_free_areas(); @@ -72,6 +76,8 @@ total++; if (PageReserved(mem_map+i)) reserved++; + if (PageSwapCache(mem_map+i)) + cached++; else if (!atomic_read(&mem_map[i].count)) free++; else if (atomic_read(&mem_map[i].count) == 1) @@ -84,6 +90,7 @@ printk("%d reserved pages\n",reserved); printk("%d pages nonshared\n",nonshared); printk("%d pages shared\n",shared); + printk("%d pages swap cached\n",cached); show_buffers(); #ifdef CONFIG_NET show_net_buffers(); @@ -293,8 +300,6 @@ /* * paging_init() continues the virtual memory environment setup which * was begun by the code in arch/head.S. - * The parameters are pointers to where to stick the starting and ending - * addresses of available kernel virtual memory. */ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) @@ -321,6 +326,18 @@ for (i = 0; i < 16; i++) pgprot_val(protection_map[i]) |= _PAGE_CACHE040; } + /* Fix the PAGE_NONE value. */ + if (CPU_IS_040_OR_060) { + /* On the 680[46]0 we can use the _PAGE_SUPER bit. */ + pgprot_val(protection_map[0]) |= _PAGE_SUPER; + pgprot_val(protection_map[VM_SHARED]) |= _PAGE_SUPER; + } else { + /* Otherwise we must fake it. */ + pgprot_val(protection_map[0]) &= ~_PAGE_PRESENT; + pgprot_val(protection_map[0]) |= _PAGE_FAKE_SUPER; + pgprot_val(protection_map[VM_SHARED]) &= ~_PAGE_PRESENT; + pgprot_val(protection_map[VM_SHARED]) |= _PAGE_FAKE_SUPER; + } /* * Map the physical memory available into the kernel virtual @@ -412,42 +429,15 @@ high_memory = (void *) end_mem; max_mapnr = num_physpages = MAP_NR(end_mem); - start_mem = PAGE_ALIGN(start_mem); - while (start_mem < end_mem) { - clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags); - start_mem += PAGE_SIZE; + tmp = start_mem = PAGE_ALIGN(start_mem); + while (tmp < end_mem) { + clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags); + tmp += PAGE_SIZE; } #ifdef CONFIG_ATARI - - if (MACH_IS_ATARI) { - - /* If the page with physical address 0 isn't the first kernel - * code page, it has to be reserved because the first 2 KB of - * ST-Ram can only be accessed from supervisor mode by - * hardware. - */ - - unsigned long virt0 = PTOV( 0 ), adr; - extern unsigned long rsvd_stram_beg, rsvd_stram_end; - - if (virt0 != 0) { - - set_bit(PG_reserved, &mem_map[MAP_NR(virt0)].flags); - - /* Also, reserve all pages that have been marked by - * stram_alloc() (e.g. for the screen memory). (This may - * treat the first ST-Ram page a second time, but that - * doesn't hurt...) */ - - rsvd_stram_end += PAGE_SIZE - 1; - rsvd_stram_end &= PAGE_MASK; - rsvd_stram_beg &= PAGE_MASK; - for( adr = rsvd_stram_beg; adr < rsvd_stram_end; adr += PAGE_SIZE ) - set_bit(PG_reserved, &mem_map[MAP_NR(adr)].flags); - } - } - + if (MACH_IS_ATARI) + atari_stram_reserve_pages( start_mem ); #endif for (tmp = 0 ; tmp < end_mem ; tmp += PAGE_SIZE) { 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 Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mm/kmap.c Fri Feb 13 01:30:13 1998 @@ -0,0 +1,564 @@ +/* + * linux/arch/m68k/mm/kmap.c + * + * Copyright (C) 1997 Roman Hodek + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +extern pte_t *kernel_page_table (unsigned long *memavailp); + +/* Virtual address region for use by kernel_map() */ +#define KMAP_START 0xd0000000 +#define KMAP_END 0xf0000000 + +/* Granularity of kernel_map() allocations */ +#define KMAP_STEP (256*1024) + +/* Size of pool of KMAP structures; that is needed, because kernel_map() can + * be called at times where kmalloc() isn't initialized yet. */ +#define KMAP_POOL_SIZE 16 + +/* structure for maintainance of kmap regions */ +typedef struct kmap { + struct kmap *next, *prev; /* linking of list */ + unsigned long addr; /* start address of region */ + unsigned long mapaddr; /* address returned to user */ + unsigned long size; /* size of region */ + unsigned free : 1; /* flag whether free or allocated */ + unsigned kmalloced : 1; /* flag whether got this from kmalloc() */ + unsigned pool_alloc : 1; /* flag whether got this is alloced in pool */ +} KMAP; + +KMAP kmap_pool[KMAP_POOL_SIZE] = { + { NULL, NULL, KMAP_START, KMAP_START, KMAP_END-KMAP_START, 1, 0, 1 }, + { NULL, NULL, 0, 0, 0, 0, 0, 0 }, +}; + +/* + * anchor of kmap region list + * + * The list is always ordered by addresses, and regions are always adjacent, + * i.e. there must be no holes between them! + */ +KMAP *kmap_regions = &kmap_pool[0]; + +/* for protecting the kmap_regions list against races */ +static struct semaphore kmap_sem = MUTEX; + + + +/* + * Low-level allocation and freeing of KMAP structures + */ +static KMAP *alloc_kmap( int use_kmalloc ) +{ + KMAP *p; + int i; + + /* first try to get from the pool if possible */ + for( i = 0; i < KMAP_POOL_SIZE; ++i ) { + if (!kmap_pool[i].pool_alloc) { + kmap_pool[i].kmalloced = 0; + kmap_pool[i].pool_alloc = 1; + return( &kmap_pool[i] ); + } + } + + if (use_kmalloc && (p = (KMAP *)kmalloc( sizeof(KMAP), GFP_KERNEL ))) { + p->kmalloced = 1; + return( p ); + } + + return( NULL ); +} + +static void free_kmap( KMAP *p ) +{ + if (p->kmalloced) + kfree( p ); + else + p->pool_alloc = 0; +} + + +/* + * Get a free region from the kmap address range + */ +static KMAP *kmap_get_region( unsigned long size, int use_kmalloc ) +{ + KMAP *p, *q; + + /* look for a suitable free region */ + for( p = kmap_regions; p; p = p->next ) + if (p->free && p->size >= size) + break; + if (!p) { + printk( KERN_ERR "kernel_map: address space for " + "allocations exhausted\n" ); + return( NULL ); + } + + if (p->size > size) { + /* if free region is bigger than we need, split off the rear free part + * into a new region */ + if (!(q = alloc_kmap( use_kmalloc ))) { + printk( KERN_ERR "kernel_map: out of memory\n" ); + return( NULL ); + } + q->addr = p->addr + size; + q->size = p->size - size; + p->size = size; + q->free = 1; + + q->prev = p; + q->next = p->next; + p->next = q; + if (q->next) q->next->prev = q; + } + + p->free = 0; + return( p ); +} + + +/* + * Free a kernel_map region again + */ +static void kmap_put_region( KMAP *p ) +{ + KMAP *q; + + p->free = 1; + + /* merge with previous region if possible */ + q = p->prev; + if (q && q->free) { + if (q->addr + q->size != p->addr) { + printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" ); + return; + } + q->size += p->size; + q->next = p->next; + if (p->next) p->next->prev = q; + free_kmap( p ); + p = q; + } + + /* merge with following region if possible */ + q = p->next; + if (q && q->free) { + if (p->addr + p->size != q->addr) { + printk( KERN_ERR "kernel_malloc: allocation list destroyed\n" ); + return; + } + p->size += q->size; + p->next = q->next; + if (q->next) q->next->prev = p; + free_kmap( q ); + } +} + + +/* + * kernel_map() helpers + */ +static inline pte_t * +pte_alloc_kernel_map(pmd_t *pmd, unsigned long address, + unsigned long *memavailp) +{ + address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + if (pmd_none(*pmd)) { + pte_t *page = kernel_page_table(memavailp); + if (pmd_none(*pmd)) { + if (page) { + pmd_set(pmd, page); + memset( page, 0, PAGE_SIZE ); + return page + address; + } + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + if (memavailp) + panic("kernel_map: slept during init?!?"); + cache_page((unsigned long) page); + free_page((unsigned long) page); + } + if (pmd_bad(*pmd)) { + printk( KERN_ERR "Bad pmd in pte_alloc_kernel_map: %08lx\n", + pmd_val(*pmd)); + pmd_set(pmd, BAD_PAGETABLE); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + address; +} + +static inline void +kernel_map_pte(pte_t *pte, unsigned long address, unsigned long size, + unsigned long phys_addr, pgprot_t prot) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_val(*pte) = phys_addr + pgprot_val(prot); + address += PAGE_SIZE; + phys_addr += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline int +kernel_map_pmd (pmd_t *pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, pgprot_t prot, + unsigned long *memavailp) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + phys_addr -= address; + + if (CPU_IS_040_OR_060) { + do { + pte_t *pte = pte_alloc_kernel_map(pmd, address, memavailp); + if (!pte) + return -ENOMEM; + kernel_map_pte(pte, address, end - address, + address + phys_addr, prot); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + } else { + /* On the 68030 we use early termination page descriptors. + Each one points to 64 pages (256K). */ + int i = (address >> (PMD_SHIFT-4)) & 15; + do { + (&pmd_val(*pmd))[i++] = (address + phys_addr) | pgprot_val(prot); + address += PMD_SIZE / 16; + } while (address < end); + } + return 0; +} + + +/* + * Map some physical address range into the kernel address space. The + * code is copied and adapted from map_chunk(). + */ +/* Rewritten by Andreas Schwab to remove all races. */ + +unsigned long kernel_map(unsigned long phys_addr, unsigned long size, + int cacheflag, unsigned long *memavailp) +{ + unsigned long retaddr, from, end; + pgd_t *dir; + pgprot_t prot; + KMAP *kmap; + + /* Round down 'phys_addr' to 256 KB and adjust size */ + retaddr = phys_addr & (KMAP_STEP-1); + size += retaddr; + phys_addr &= ~(KMAP_STEP-1); + /* Round up the size to 256 KB. It doesn't hurt if too much is + mapped... */ + size = (size + KMAP_STEP - 1) & ~(KMAP_STEP-1); + + down( &kmap_sem ); + if (!(kmap = kmap_get_region( size, memavailp == NULL ))) + return( 0 ); + from = kmap->addr; + retaddr += from; + kmap->mapaddr = retaddr; + end = from + size; + up( &kmap_sem ); + + if (CPU_IS_040_OR_060) { + pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_GLOBAL040 | + _PAGE_ACCESSED | _PAGE_DIRTY); + switch (cacheflag) { + case KERNELMAP_FULL_CACHING: + pgprot_val(prot) |= _PAGE_CACHE040; + break; + case KERNELMAP_NOCACHE_SER: + default: + pgprot_val(prot) |= _PAGE_NOCACHE_S; + break; + case KERNELMAP_NOCACHE_NONSER: + pgprot_val(prot) |= _PAGE_NOCACHE; + break; + case KERNELMAP_NO_COPYBACK: + pgprot_val(prot) |= _PAGE_CACHE040W; + break; + } + } else + pgprot_val(prot) = (_PAGE_PRESENT | _PAGE_ACCESSED | + _PAGE_DIRTY | + ((cacheflag == KERNELMAP_FULL_CACHING || + cacheflag == KERNELMAP_NO_COPYBACK) + ? 0 : _PAGE_NOCACHE030)); + + phys_addr -= from; + dir = pgd_offset_k(from); + while (from < end) { + pmd_t *pmd = pmd_alloc_kernel(dir, from); + + if (kernel_map_pmd(pmd, from, end - from, phys_addr + from, + prot, memavailp)) { + printk( KERN_ERR "kernel_map: out of memory\n" ); + return 0UL; + } + from = (from + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + + return retaddr; +} + + +/* + * kernel_unmap() helpers + */ +static inline void pte_free_kernel_unmap( pmd_t *pmd ) +{ + unsigned long page = pmd_page(*pmd); + mem_map_t *pagemap = &mem_map[MAP_NR(page)]; + + pmd_clear(pmd); + cache_page(page); + + if (PageReserved( pagemap )) { + /* need to unreserve pages that were allocated with memavailp != NULL; + * this works only if 'page' is page-aligned */ + if (page & ~PAGE_MASK) + return; + clear_bit( PG_reserved, &pagemap->flags ); + atomic_set( &pagemap->count, 1 ); + } + free_page( page ); +} + +/* + * This not only unmaps the requested region, but also loops over the whole + * pmd to determine whether the other pte's are clear (so that the page can be + * freed.) If so, it returns 1, 0 otherwise. + */ +static inline int +kernel_unmap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size) +{ + pte_t *pte; + unsigned long addr2, end, end2; + int all_clear = 1; + + if (pmd_none(*pmd)) + return( 0 ); + if (pmd_bad(*pmd)) { + printk( KERN_ERR "kernel_unmap_pte_range: bad pmd (%08lx)\n", + pmd_val(*pmd) ); + pmd_clear(pmd); + return( 0 ); + } + address &= ~PMD_MASK; + addr2 = 0; + pte = pte_offset(pmd, addr2); + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + end2 = addr2 + PMD_SIZE; + while( addr2 < end2 ) { + if (!pte_none(*pte)) { + if (address <= addr2 && addr2 < end) + pte_clear(pte); + else + all_clear = 0; + } + ++pte; + addr2 += PAGE_SIZE; + } + return( all_clear ); +} + +static inline void +kernel_unmap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size) +{ + pmd_t * pmd; + unsigned long end; + + if (pgd_none(*dir)) + return; + if (pgd_bad(*dir)) { + printk( KERN_ERR "kernel_unmap_pmd_range: bad pgd (%08lx)\n", + pgd_val(*dir) ); + pgd_clear(dir); + return; + } + pmd = pmd_offset(dir, address); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + + if (CPU_IS_040_OR_060) { + do { + if (kernel_unmap_pte_range(pmd, address, end - address)) + pte_free_kernel_unmap( pmd ); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + } else { + /* On the 68030 clear the early termination descriptors */ + int i = (address >> (PMD_SHIFT-4)) & 15; + do { + (&pmd_val(*pmd))[i++] = 0; + address += PMD_SIZE / 16; + } while (address < end); + } +} + +/* + * Unmap a kernel_map()ed region again + */ +void kernel_unmap( unsigned long addr ) +{ + unsigned long end; + pgd_t *dir; + KMAP *p; + + down( &kmap_sem ); + + /* find region for 'addr' in list; must search for mapaddr! */ + for( p = kmap_regions; p; p = p->next ) + if (!p->free && p->mapaddr == addr) + break; + if (!p) { + printk( KERN_ERR "kernel_unmap: trying to free invalid region\n" ); + return; + } + addr = p->addr; + end = addr + p->size; + kmap_put_region( p ); + + dir = pgd_offset_k( addr ); + while( addr < end ) { + kernel_unmap_pmd_range( dir, addr, end - addr ); + addr = (addr + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + + up( &kmap_sem ); + /* flushing for a range would do, but there's no such function for kernel + * address space... */ + flush_tlb_all(); +} + + +/* + * kernel_set_cachemode() helpers + */ +static inline void set_cmode_pte( pmd_t *pmd, unsigned long address, + unsigned long size, unsigned cmode ) +{ pte_t *pte; + unsigned long end; + + if (pmd_none(*pmd)) + return; + + pte = pte_offset( pmd, address ); + address &= ~PMD_MASK; + end = address + size; + if (end >= PMD_SIZE) + end = PMD_SIZE; + + for( ; address < end; pte++ ) { + pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode; + address += PAGE_SIZE; + } +} + + +static inline void set_cmode_pmd( pgd_t *dir, unsigned long address, + unsigned long size, unsigned cmode ) +{ + pmd_t *pmd; + unsigned long end; + + if (pgd_none(*dir)) + return; + + pmd = pmd_offset( dir, address ); + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + + if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) { + /* 68030 early termination descriptor */ + pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode; + return; + } + else { + /* "normal" tables */ + for( ; address < end; pmd++ ) { + set_cmode_pte( pmd, address, end - address, cmode ); + address = (address + PMD_SIZE) & PMD_MASK; + } + } +} + + +/* + * Set new cache mode for some kernel address space. + * The caller must push data for that range itself, if such data may already + * be in the cache. + */ +void kernel_set_cachemode( unsigned long address, unsigned long size, + unsigned cmode ) +{ + pgd_t *dir = pgd_offset_k( address ); + unsigned long end = address + size; + + if (CPU_IS_040_OR_060) { + switch( cmode ) { + case KERNELMAP_FULL_CACHING: + cmode = _PAGE_CACHE040; + break; + case KERNELMAP_NOCACHE_SER: + default: + cmode = _PAGE_NOCACHE_S; + break; + case KERNELMAP_NOCACHE_NONSER: + cmode = _PAGE_NOCACHE; + break; + case KERNELMAP_NO_COPYBACK: + cmode = _PAGE_CACHE040W; + break; + } + } else + cmode = ((cmode == KERNELMAP_FULL_CACHING || + cmode == KERNELMAP_NO_COPYBACK) ? + 0 : _PAGE_NOCACHE030); + + for( ; address < end; dir++ ) { + set_cmode_pmd( dir, address, end - address, cmode ); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + } + /* flushing for a range would do, but there's no such function for kernel + * address space... */ + flush_tlb_all(); +} 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 Mon Jul 7 17:18:53 1997 +++ new/linux/arch/m68k/mm/memory.c Fri Feb 13 01:30:13 1998 @@ -18,8 +18,6 @@ #include #include -extern pte_t *kernel_page_table (unsigned long *memavailp); - /* Strings for `extern inline' functions in . If put directly into these functions, they are output for every file that includes pgtable.h */ @@ -349,10 +347,10 @@ /* no match, too, so get the actual physical address from the MMU. */ if (CPU_IS_060) { - unsigned long fs = get_fs(); + mm_segment_t fs = get_fs(); unsigned long paddr; - set_fs (SUPER_DATA); + set_fs (MAKE_MM_SEG(SUPER_DATA)); /* The PLPAR instruction causes an access error if the translation * is not possible. We don't catch that here, so a bad kernel trap @@ -368,9 +366,9 @@ } else if (CPU_IS_040) { unsigned long mmusr; - unsigned long fs = get_fs(); + mm_segment_t fs = get_fs(); - set_fs (SUPER_DATA); + set_fs (MAKE_MM_SEG(SUPER_DATA)); asm volatile (".chip 68040\n\t" "ptestr (%1)\n\t" @@ -380,6 +378,9 @@ : "a" (vaddr)); set_fs (fs); + if (mmusr & MMU_T_040) { + return (vaddr); /* Transparent translation */ + } if (mmusr & MMU_R_040) return (mmusr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1)); @@ -452,7 +453,7 @@ /* * if on an amiga and address is in first 16M, move it - * to the ZTWO_ADDR range + * to the ZTWO_VADDR range */ if (MACH_IS_AMIGA && paddr < 16*1024*1024) return ZTWO_VADDR(paddr); @@ -495,33 +496,6 @@ if (CPU_IS_060) cleari040(paddr); \ } while(0) -/* push page defined by virtual address in both caches */ -#define pushv040(vaddr) \ - do { unsigned long _tmp1, _tmp2; \ - __asm__ __volatile__ ("nop\n\t" \ - ".chip 68040\n\t" \ - "ptestr (%2)\n\t" \ - "movec %%mmusr,%0\n\t" \ - "andw #0xf000,%0\n\t" \ - "movel %0,%1\n\t" \ - "nop\n\t" \ - "cpushp %%bc,(%1)\n\t" \ - ".chip 68k" \ - : "=d" (_tmp1), "=a" (_tmp2) \ - : "a" (vaddr)); \ - } while (0) - -/* push page defined by virtual address in both caches */ -#define pushv060(vaddr) \ - do { unsigned long _tmp; \ - __asm__ __volatile__ (".chip 68060\n\t" \ - "plpar (%0)\n\t" \ - "cpushp %%bc,(%0)\n\t" \ - ".chip 68k" \ - : "=a" (_tmp) \ - : "0" (vaddr)); \ - } while (0) - /* * 040: Hit every page containing an address in the range paddr..paddr+len-1. @@ -632,64 +606,11 @@ } -/* - * cache_push_v() semantics: Write back any dirty cache data in the given - * area, and invalidate those entries at least in the instruction cache. This - * is intended to be used after data has been written that can be executed as - * code later. The range is defined by a _user_mode_ _virtual_ address (or, - * more exactly, the space is defined by the %sfc/%dfc register.) - */ - -void cache_push_v (unsigned long vaddr, int len) -{ - if (CPU_IS_040) { - int tmp = PAGE_SIZE; - - /* on 68040, push cache lines for pages in the range */ - len += vaddr & (PAGE_SIZE - 1); - - /* - * Work around bug I17 in the 68060 affecting some instruction - * lines not being invalidated properly. - */ - vaddr &= PAGE_MASK; - - do { - pushv040(vaddr); - vaddr += tmp; - } while ((len -= tmp) > 0); - } - else if (CPU_IS_060) { - int tmp = PAGE_SIZE; - - /* on 68040, push cache lines for pages in the range */ - len += vaddr & (PAGE_SIZE - 1); - do { - pushv060(vaddr); - vaddr += tmp; - } while ((len -= tmp) > 0); - } - /* 68030/68020 have no writeback cache; still need to clear icache. */ - else /* 68030 or 68020 */ - asm volatile ("movec %/cacr,%/d0\n\t" - "oriw %0,%/d0\n\t" - "movec %/d0,%/cacr" - : : "i" (FLUSH_I) - : "d0"); -} - #undef clear040 #undef cleari040 #undef push040 #undef pushcl040 #undef pushcli040 -#undef pushv040 -#undef pushv060 - -unsigned long mm_phys_to_virt (unsigned long addr) -{ - return PTOV (addr); -} int mm_end_of_chunk (unsigned long addr, int len) { @@ -700,227 +621,4 @@ return 1; return 0; } - -/* Map some physical address range into the kernel address space. The - * code is copied and adapted from map_chunk(). - */ - -unsigned long kernel_map(unsigned long paddr, unsigned long size, - int nocacheflag, unsigned long *memavailp ) -{ -#define STEP_SIZE (256*1024) - - static unsigned long vaddr = 0xe0000000; /* safe place */ - unsigned long physaddr, retaddr; - pte_t *ktablep = NULL; - pmd_t *kpointerp; - pgd_t *page_dir; - int pindex; /* index into pointer table */ - int prot; - - /* Round down 'paddr' to 256 KB and adjust size */ - physaddr = paddr & ~(STEP_SIZE-1); - size += paddr - physaddr; - retaddr = vaddr + (paddr - physaddr); - paddr = physaddr; - /* Round up the size to 256 KB. It doesn't hurt if too much is - * mapped... */ - size = (size + STEP_SIZE - 1) & ~(STEP_SIZE-1); - - if (CPU_IS_040_OR_060) { - prot = _PAGE_PRESENT | _PAGE_GLOBAL040; - switch( nocacheflag ) { - case KERNELMAP_FULL_CACHING: - prot |= _PAGE_CACHE040; - break; - case KERNELMAP_NOCACHE_SER: - default: - prot |= _PAGE_NOCACHE_S; - break; - case KERNELMAP_NOCACHE_NONSER: - prot |= _PAGE_NOCACHE; - break; - case KERNELMAP_NO_COPYBACK: - prot |= _PAGE_CACHE040W; - /* prot |= 0; */ - break; - } - } else - prot = _PAGE_PRESENT | - ((nocacheflag == KERNELMAP_FULL_CACHING || - nocacheflag == KERNELMAP_NO_COPYBACK) ? 0 : _PAGE_NOCACHE030); - - page_dir = pgd_offset_k(vaddr); - if (pgd_present(*page_dir)) { - kpointerp = (pmd_t *)pgd_page(*page_dir); - pindex = (vaddr >> 18) & 0x7f; - if (pindex != 0 && CPU_IS_040_OR_060) { - if (pmd_present(*kpointerp)) - ktablep = (pte_t *)pmd_page(*kpointerp); - else { - ktablep = kernel_page_table (memavailp); - /* Make entries invalid */ - memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE); - pmd_set(kpointerp,ktablep); - } - ktablep += (pindex & 15)*64; - } - } - else { - /* we need a new pointer table */ - kpointerp = get_kpointer_table (); - pgd_set(page_dir, (pmd_t *)kpointerp); - memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t)); - pindex = 0; - } - - for (physaddr = paddr; physaddr < paddr + size; vaddr += STEP_SIZE) { - - if (pindex > 127) { - /* we need a new pointer table */ - kpointerp = get_kpointer_table (); - pgd_set(pgd_offset_k(vaddr), (pmd_t *)kpointerp); - memset( kpointerp, 0, PTRS_PER_PMD*sizeof(pmd_t)); - pindex = 0; - } - - if (CPU_IS_040_OR_060) { - int i; - unsigned long ktable; - - /* - * 68040, use page tables pointed to by the - * kernel pointer table. - */ - - if ((pindex & 15) == 0) { - /* Need new page table every 4M on the '040 */ - ktablep = kernel_page_table (memavailp); - /* Make entries invalid */ - memset( ktablep, 0, sizeof(long)*PTRS_PER_PTE); - } - - ktable = VTOP(ktablep); - - /* - * initialize section of the page table mapping - * this 1M portion. - */ - for (i = 0; i < 64; i++) { - pte_val(*ktablep++) = physaddr | prot; - physaddr += PAGE_SIZE; - } - - /* - * make the kernel pointer table point to the - * kernel page table. - */ - - ((unsigned long *)kpointerp)[pindex++] = ktable | _PAGE_TABLE; - - } else { - /* - * 68030, use early termination page descriptors. - * Each one points to 64 pages (256K). - */ - ((unsigned long *)kpointerp)[pindex++] = physaddr | prot; - physaddr += 64 * PAGE_SIZE; - } - } - - return( retaddr ); -} - - -static inline void set_cmode_pte( pmd_t *pmd, unsigned long address, - unsigned long size, unsigned cmode ) -{ pte_t *pte; - unsigned long end; - - if (pmd_none(*pmd)) - return; - - pte = pte_offset( pmd, address ); - address &= ~PMD_MASK; - end = address + size; - if (end >= PMD_SIZE) - end = PMD_SIZE; - - for( ; address < end; pte++ ) { - pte_val(*pte) = (pte_val(*pte) & ~_PAGE_NOCACHE) | cmode; - address += PAGE_SIZE; - } -} - - -static inline void set_cmode_pmd( pgd_t *dir, unsigned long address, - unsigned long size, unsigned cmode ) -{ - pmd_t *pmd; - unsigned long end; - - if (pgd_none(*dir)) - return; - - pmd = pmd_offset( dir, address ); - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - - if ((pmd_val(*pmd) & _DESCTYPE_MASK) == _PAGE_PRESENT) { - /* 68030 early termination descriptor */ - pmd_val(*pmd) = (pmd_val(*pmd) & ~_PAGE_NOCACHE) | cmode; - return; - } - else { - /* "normal" tables */ - for( ; address < end; pmd++ ) { - set_cmode_pte( pmd, address, end - address, cmode ); - address = (address + PMD_SIZE) & PMD_MASK; - } - } -} - - -/* - * Set new cache mode for some kernel address space. - * The caller must push data for that range itself, if such data may already - * be in the cache. - */ - -void kernel_set_cachemode( unsigned long address, unsigned long size, - unsigned cmode ) -{ - pgd_t *dir = pgd_offset_k( address ); - unsigned long end = address + size; - - if (CPU_IS_040_OR_060) { - switch( cmode ) { - case KERNELMAP_FULL_CACHING: - cmode = _PAGE_CACHE040; - break; - case KERNELMAP_NOCACHE_SER: - default: - cmode = _PAGE_NOCACHE_S; - break; - case KERNELMAP_NOCACHE_NONSER: - cmode = _PAGE_NOCACHE; - break; - case KERNELMAP_NO_COPYBACK: - cmode = _PAGE_CACHE040W; - break; - } - } else - cmode = ((cmode == KERNELMAP_FULL_CACHING || - cmode == KERNELMAP_NO_COPYBACK) ? - 0 : _PAGE_NOCACHE030); - - for( ; address < end; dir++ ) { - set_cmode_pmd( dir, address, end - address, cmode ); - address = (address + PGDIR_SIZE) & PGDIR_MASK; - } - flush_tlb_all(); -} - diff -ur --new-file old/linux/arch/m68k/mvme16x/16xints.c new/linux/arch/m68k/mvme16x/16xints.c --- old/linux/arch/m68k/mvme16x/16xints.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mvme16x/16xints.c Sat Feb 21 03:28:21 1998 @@ -0,0 +1,143 @@ +/* + * arch/m68k/mvme16x/16xints.c + * + * Copyright (C) 1995 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 + +static void mvme16x_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[192]; + +/* + * void mvme16x_init_IRQ (void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function is called during kernel startup to initialize + * the mvme16x IRQ handling routines. Should probably ensure + * that the base vectors for the VMEChip2 and PCCChip2 are valid. + */ + +void mvme16x_init_IRQ (void) +{ + int i; + + for (i = 0; i < 192; i++) { + irq_tab[i].handler = mvme16x_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 mvme16x_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + if (irq < 64 || irq > 255) { + printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, irq, devname); + return -ENXIO; + } + + if (!(irq_tab[irq-64].flags & IRQ_FLG_STD)) { + if (irq_tab[irq-64].flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, irq_tab[irq-64].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-64].devname); + return -EBUSY; + } + } + irq_tab[irq-64].handler = handler; + irq_tab[irq-64].flags = flags; + irq_tab[irq-64].dev_id = dev_id; + irq_tab[irq-64].devname = devname; + return 0; +} + +void mvme16x_free_irq(unsigned int irq, void *dev_id) +{ + if (irq < 64 || irq > 255) { + printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (irq_tab[irq-64].dev_id != dev_id) + printk("%s: Removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, irq_tab[irq-64].devname); + + irq_tab[irq-64].handler = mvme16x_defhand;; + irq_tab[irq-64].flags = IRQ_FLG_STD; + irq_tab[irq-64].dev_id = NULL; + irq_tab[irq-64].devname = NULL; +} + +void mvme16x_process_int (unsigned long vec, struct pt_regs *fp) +{ + if (vec < 64 || vec > 255) + panic ("mvme16x_process_int: Illegal vector %ld", vec); + irq_tab[vec-64].count++; + irq_tab[vec-64].handler(vec, irq_tab[vec-64].dev_id, fp); +} + +int mvme16x_get_irq_list (char *buf) +{ + int i, len = 0; + + for (i = 0; i < 192; i++) { + if (irq_tab[i].count) + len += sprintf (buf+len, "Vec 0x%02x: %8d %s\n", + i+64, irq_tab[i].count, + irq_tab[i].devname ? irq_tab[i].devname : "free"); + } + return len; +} + + +static void mvme16x_defhand (int irq, void *dev_id, struct pt_regs *fp) +{ + panic ("Unknown interrupt 0x%02x", irq); +} + + +void mvme16x_enable_irq (unsigned int irq) +{ +} + + +void mvme16x_disable_irq (unsigned int irq) +{ +} + + diff -ur --new-file old/linux/arch/m68k/mvme16x/Makefile new/linux/arch/m68k/mvme16x/Makefile --- old/linux/arch/m68k/mvme16x/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mvme16x/Makefile Fri Feb 13 01:30:13 1998 @@ -0,0 +1,14 @@ +# +# Makefile for Linux arch/m68k/mvme16x 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 := mvme16x.o +O_OBJS := config.o 16xints.o +#OX_OBJS = ksyms.o + +include $(TOPDIR)/Rules.make 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 Thu Jan 1 01:00:00 1970 +++ new/linux/arch/m68k/mvme16x/config.c Fri Feb 13 01:30:13 1998 @@ -0,0 +1,403 @@ +/* + * arch/m68k/mvme16x/config.c + * + * Copyright (C) 1995 Richard Hirst [richard@sleepie.demon.co.uk] + * + * Based on: + * + * linux/amiga/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 + +typedef struct { + unsigned char + ctrl, + bcd_sec, + bcd_min, + bcd_hr, + bcd_dow, + bcd_dom, + bcd_mth, + bcd_year; +} MK48T08; + +#define RTC_WRITE 0x80 +#define RTC_READ 0x40 +#define RTC_STOP 0x20 + +int atari_SCC_reset_done = 1; /* So SCC doesn't get reset */ +u_long atari_mch_cookie = 0; + +MK48T08 * volatile rtc = (MK48T08 *)0xfffc1ff8; + +extern void mvme16x_process_int (int level, struct pt_regs *regs); +extern void mvme16x_init_IRQ (void); +extern void mvme16x_free_irq (unsigned int, void *); +extern int mvme16x_get_irq_list (char *); +extern void mvme16x_enable_irq (unsigned int); +extern void mvme16x_disable_irq (unsigned int); +static void mvme16x_get_model(char *model); +static int mvme16x_get_hardware_list(char *buffer); +extern int mvme16x_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id); +extern void mvme16x_sched_init(void (*handler)(int, void *, struct pt_regs *)); +extern int mvme16x_keyb_init(void); +extern int mvme16x_kbdrate (struct kbd_repeat *); +extern unsigned long mvme16x_gettimeoffset (void); +extern void mvme16x_gettod (int *year, int *mon, int *day, int *hour, + int *min, int *sec); +extern int mvme16x_hwclk (int, struct hwclk_time *); +extern int mvme16x_set_clock_mmss (unsigned long); +extern void mvme16x_check_partition (struct gendisk *hd, unsigned int dev); +extern void mvme16x_mksound( unsigned int count, unsigned int ticks ); +extern void mvme16x_reset (void); +extern void mvme16x_waitbut(void); + +int bcd2int (unsigned char b); + +/* Save tick handler routine pointer, will point to do_timer() in + * kernel/sched.c, called via mvme16x_process_int() */ + +static void (*tick_handler)(int, void *, struct pt_regs *); + + +unsigned short mvme16x_config; + + +int mvme16x_kbdrate (struct kbd_repeat *k) +{ + return 0; +} + +void mvme16x_mksound( unsigned int count, unsigned int ticks ) +{ +} + +void mvme16x_reset() +{ + printk ("\r\n\nCalled mvme16x_reset\r\n" + "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r"); + /* The string of returns is to delay the reset until the whole + * message is output. Assert reset bit in GCSR */ + *(volatile char *)0xfff40107 = 0x80; +} + +static void mvme16x_get_model(char *model) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + char suf[4]; + + suf[1] = p->brdsuffix[0]; + suf[2] = p->brdsuffix[1]; + suf[3] = '\0'; + suf[0] = suf[1] ? '-' : '\0'; + + sprintf(model, "Motorola MVME%x%s", p->brdno, suf); +} + + +static int mvme16x_get_hardware_list(char *buffer) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + int len = 0; + + if (p->brdno == 0x0162 || p->brdno == 0x0172) + { + unsigned char rev = *(unsigned char *)MVME162_VERSION_REG; + + len += sprintf (buffer+len, "VMEchip2 %spresent\n", + rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : ""); + len += sprintf (buffer+len, "SCSI interface %spresent\n", + rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : ""); + len += sprintf (buffer+len, "Ethernet i/f %spresent\n", + rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : ""); + } + else + *buffer = '\0'; + + return (len); +} + + +__initfunc(void config_mvme16x(void)) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + char id[40]; + + mach_sched_init = mvme16x_sched_init; + mach_keyb_init = mvme16x_keyb_init; + mach_kbdrate = mvme16x_kbdrate; + mach_init_IRQ = mvme16x_init_IRQ; + mach_gettimeoffset = mvme16x_gettimeoffset; + mach_gettod = mvme16x_gettod; + mach_hwclk = mvme16x_hwclk; + mach_set_clock_mmss = mvme16x_set_clock_mmss; +/* kd_mksound = mvme16x_mksound; */ + mach_reset = mvme16x_reset; + mach_free_irq = mvme16x_free_irq; + mach_process_int = mvme16x_process_int; + mach_get_irq_list = mvme16x_get_irq_list; + mach_request_irq = mvme16x_request_irq; + enable_irq = mvme16x_enable_irq; + disable_irq = mvme16x_disable_irq; + mach_get_model = mvme16x_get_model; + mach_get_hardware_list = mvme16x_get_hardware_list; + + /* Report board revision */ + + if (strncmp("BDID", p->bdid, 4)) + { + printk ("\n\nBug call .BRD_ID returned garbage - giving up\n\n"); + while (1) + ; + } + mvme16x_get_model(id); + printk ("\nBRD_ID: %s BUG %x.%x %02x/%02x/%02x\n", id, p->rev>>4, + p->rev&0xf, p->yr, p->mth, p->day); + if (p->brdno == 0x0162 || p->brdno == 0x172) + { + unsigned char rev = *(unsigned char *)MVME162_VERSION_REG; + + mvme16x_config = rev | MVME16x_CONFIG_GOT_SCCA; + + printk ("MVME%x Hardware status:\n", p->brdno); + printk (" CPU Type 68%s040\n", + rev & MVME16x_CONFIG_GOT_FPU ? "" : "LC"); + printk (" CPU clock %dMHz\n", + rev & MVME16x_CONFIG_SPEED_32 ? 32 : 25); + printk (" VMEchip2 %spresent\n", + rev & MVME16x_CONFIG_NO_VMECHIP2 ? "NOT " : ""); + printk (" SCSI interface %spresent\n", + rev & MVME16x_CONFIG_NO_SCSICHIP ? "NOT " : ""); + printk (" Ethernet interface %spresent\n", + rev & MVME16x_CONFIG_NO_ETHERNET ? "NOT " : ""); + } + else + mvme16x_config = MVME16x_CONFIG_GOT_LP | MVME16x_CONFIG_GOT_CD2401; +} + +static void mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp) +{ + *(volatile unsigned char *)0xfff4201b |= 8; + tick_handler(irq, dev_id, fp); +} + +void mvme16x_sched_init (void (*timer_routine)(int, void *, struct pt_regs *)) +{ + tick_handler = timer_routine; + /* Using PCCchip2 or MC2 chip tick timer 1 */ + *(volatile unsigned long *)0xfff42008 = 0; + *(volatile unsigned long *)0xfff42004 = 10000; /* 10ms */ + *(volatile unsigned char *)0xfff42017 |= 3; + *(volatile unsigned char *)0xfff4201b = 0x16; + if (request_irq(IRQ_MVME16x_TIMER, mvme16x_timer_int, 0, + "timer", mvme16x_timer_int)) + panic ("Couldn't register timer int"); +} + + +/* This is always executed with interrupts disabled. */ +unsigned long mvme16x_gettimeoffset (void) +{ + return (*(volatile unsigned long *)0xfff42008); +} + +extern void mvme16x_gettod (int *year, int *mon, int *day, int *hour, + int *min, int *sec) +{ + rtc->ctrl = RTC_READ; + *year = bcd2int (rtc->bcd_year); + *mon = bcd2int (rtc->bcd_mth); + *day = bcd2int (rtc->bcd_dom); + *hour = bcd2int (rtc->bcd_hr); + *min = bcd2int (rtc->bcd_min); + *sec = bcd2int (rtc->bcd_sec); + rtc->ctrl = 0; +} + +int bcd2int (unsigned char b) +{ + return ((b>>4)*10 + (b&15)); +} + +int mvme16x_hwclk(int op, struct hwclk_time *t) +{ + return 0; +} + +int mvme16x_set_clock_mmss (unsigned long nowtime) +{ + return 0; +} + +/* + * console_map_init(), here to avoid having to modify drivers/block/genhd.c + */ + +void console_map_init(void) +{ +} + +/* + * fbmem_init(), here to avoid having to modify drivers/char/mem.c + */ + +void fbmem_init(void) +{ +} + +/* Avoid mods to drivers/char/tty_io.c */ + +unsigned long con_init(unsigned long kmem_start) +{ + return (kmem_start); +} + +/* Avoid mods to drivers/char/tty_io.c */ + +int vcs_init(void) +{ + return (0); +} + +/* Avoid mods to drivers/char/tty_io.c */ + +int kbd_init(void) +{ + return (0); +} + +/* Avoid mods to init/main.c */ + +void no_scroll(char *str, int *ints) +{ +} + +/* Avoid mods to kernel/panic.c */ + +void do_unblank_screen(void) +{ +} + +int mvme16x_keyb_init (void) +{ + return 0; +} + +void mvme16x_set_vectors (void) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + unsigned long *new = (unsigned long *)vectors; + unsigned long *old = (unsigned long *)0xffe00000;; + + *(new+4) = *(old+4); /* Illegal instruction */ + *(new+9) = *(old+9); /* Trace */ + *(new+47) = *(old+47); /* Trap #15 */ + + if (p->brdno == 0x0162 || p->brdno == 0x172) + *(new+0x5e) = *(old+0x5e); /* ABORT switch */ + else + *(new+0x6e) = *(old+0x6e); /* ABORT switch */ +} + +/*------------------- Serial console stuff ------------------------*/ + +extern void mvme167_serial_console_setup(int cflag); +extern void serial167_write(struct console *co, const char *str, unsigned cnt); +extern void vme_scc_write(struct console *co, const char *str, unsigned cnt); + + +void mvme16x_init_console_port (struct console *co, int cflag) +{ + p_bdid p = (p_bdid)mvme_bdid_ptr; + + switch (p->brdno) + { +#ifdef CONFIG_MVME162_SCC + case 0x0162: + case 0x0172: + co->write = vme_scc_write; + return; +#endif +#ifdef CONFIG_SERIAL167 + case 0x0166: + case 0x0167: + case 0x0176: + case 0x0177: + co->write = serial167_write; + mvme167_serial_console_setup (cflag); + return; +#endif + default: + panic ("No console support for MVME%x\n", p->brdno); + } + return; +} + + +#ifdef CONFIG_MVME162_SCC + +static void scc_delay (void) +{ + int n; + char i; + + for (n = 0; n < 20; n++) + i = *(volatile char *)0; +} + +static void scc_write (char ch) +{ + volatile char *p = (volatile char *)SCC_A_ADDR; + + do { + scc_delay(); + } + while (!(*p & 4)); + scc_delay(); + *p = 8; + scc_delay(); + *p = ch; +} + + +void vme_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); +} +#endif diff -ur --new-file old/linux/arch/m68k/vmlinux.lds new/linux/arch/m68k/vmlinux.lds --- old/linux/arch/m68k/vmlinux.lds Sat May 24 18:10:22 1997 +++ new/linux/arch/m68k/vmlinux.lds Fri Feb 13 01:30:13 1998 @@ -31,8 +31,7 @@ CONSTRUCTORS } - . = ALIGN(8192); - init_task : { *(init_task) } /* The initial task and kernel stack */ + .bss : { *(.bss) } /* BSS */ _edata = .; /* End of data section */ @@ -40,13 +39,11 @@ __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } - . = ALIGN(4096); + . = ALIGN(8192); __init_end = .; - __bss_start = .; /* BSS */ - .bss : { - *(.bss) - } + init_task : { *(init_task) } /* The initial task and kernel stack */ + _end = . ; /* Stabs debugging sections. */ diff -ur --new-file old/linux/arch/mips/Makefile new/linux/arch/mips/Makefile --- old/linux/arch/mips/Makefile Wed Dec 10 19:31:09 1997 +++ new/linux/arch/mips/Makefile Wed Feb 25 07:08:01 1998 @@ -65,7 +65,7 @@ endif # -# CPU dependand compiler/assembler options for optimization. +# CPU-dependent compiler/assembler options for optimization. # ifdef CONFIG_CPU_R3000 CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1 @@ -93,7 +93,7 @@ endif # -# Board dependand options and extra files +# Board-dependent options and extra files # ifdef CONFIG_ALGOR_P4032 CORE_FILES += arch/mips/algor/algor.o diff -ur --new-file old/linux/arch/mips/config.in new/linux/arch/mips/config.in --- old/linux/arch/mips/config.in Wed Dec 10 19:31:09 1997 +++ new/linux/arch/mips/config.in Tue Mar 10 23:43:13 1998 @@ -109,7 +109,7 @@ bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD + bool 'Kernel module loader' CONFIG_KMOD fi source drivers/block/Config.in diff -ur --new-file old/linux/arch/mips/dec/setup.c new/linux/arch/mips/dec/setup.c --- old/linux/arch/mips/dec/setup.c Thu Jun 26 21:33:37 1997 +++ new/linux/arch/mips/dec/setup.c Wed Feb 25 07:08:01 1998 @@ -1,5 +1,5 @@ /* - * Setup pointers to hardware dependand routines. + * Setup pointers to hardware-dependent routines. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff -ur --new-file old/linux/arch/mips/deskstation/setup.c new/linux/arch/mips/deskstation/setup.c --- old/linux/arch/mips/deskstation/setup.c Wed Dec 10 19:31:09 1997 +++ new/linux/arch/mips/deskstation/setup.c Wed Feb 25 07:08:01 1998 @@ -1,5 +1,5 @@ /* - * Setup pointers to hardware dependand routines. + * Setup pointers to hardware-dependent routines. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive diff -ur --new-file old/linux/arch/mips/kernel/init_task.c new/linux/arch/mips/kernel/init_task.c --- old/linux/arch/mips/kernel/init_task.c Thu Jun 26 21:33:37 1997 +++ new/linux/arch/mips/kernel/init_task.c Tue Mar 10 22:28:59 1998 @@ -5,6 +5,7 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; +static struct files * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -ur --new-file old/linux/arch/mips/kernel/mips_ksyms.c new/linux/arch/mips/kernel/mips_ksyms.c --- old/linux/arch/mips/kernel/mips_ksyms.c Wed Dec 10 19:31:09 1997 +++ new/linux/arch/mips/kernel/mips_ksyms.c Wed Mar 18 06:15:40 1998 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -96,4 +97,8 @@ EXPORT_SYMBOL(__compute_return_epc); EXPORT_SYMBOL(register_fpe); EXPORT_SYMBOL(unregister_fpe); +#endif + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); #endif diff -ur --new-file old/linux/arch/ppc/config.in new/linux/arch/ppc/config.in --- old/linux/arch/ppc/config.in Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/config.in Tue Mar 10 23:43:13 1998 @@ -32,7 +32,7 @@ bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD + bool 'Kernel module loader' CONFIG_KMOD fi define_bool CONFIG_PCI y @@ -129,7 +129,7 @@ endmenu fi -source drivers/net/hamradio/Config.in +source net/ax25/Config.in mainmenu_option next_comment comment 'ISDN subsystem' diff -ur --new-file old/linux/arch/ppc/defconfig new/linux/arch/ppc/defconfig --- old/linux/arch/ppc/defconfig Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/defconfig Tue Mar 10 23:43:13 1998 @@ -19,7 +19,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y -CONFIG_KERNELD=y +CONFIG_KMOD=y CONFIG_PCI=y # CONFIG_PCI_OPTIMIZE is not set CONFIG_PCI_OLD_PROC=y 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 Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/kernel/idle.c Sat Feb 21 03:28:21 1998 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -236,7 +235,7 @@ * If we're interrupted we keep this page and our place in it * since we validly hold it and it's reserved for us. */ - pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 ); + pageptr = __get_free_pages(GFP_ATOMIC, 0); if ( !pageptr ) goto retry; 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 Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/kernel/irq.c Mon Feb 9 22:31:00 1998 @@ -224,10 +224,6 @@ } len += sprintf(buf+len, "\n"); } -#ifdef __SMP_PROF__ - len+=sprintf(buf+len, "IPI: %8lu received\n", - ipi_count); -#endif len += sprintf(buf+len, "99: %10u spurious or short\n", spurious_interrupts); return len; 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 Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/kernel/ppc_ksyms.c Wed Mar 18 06:15:40 1998 @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -147,3 +148,7 @@ EXPORT_SYMBOL(pci_io_base); EXPORT_SYMBOL(pci_device_loc); EXPORT_SYMBOL(note_scsi_host); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif 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 Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/kernel/prep_pci.c Sat Feb 21 03:28:21 1998 @@ -7,7 +7,6 @@ * The motherboard routes/maps will disappear shortly. -- Cort */ -#include #include #include #include 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 Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/kernel/process.c Wed Mar 18 05:56:44 1998 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include @@ -65,6 +64,7 @@ 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; diff -ur --new-file old/linux/arch/ppc/kernel/residual.c new/linux/arch/ppc/kernel/residual.c --- old/linux/arch/ppc/kernel/residual.c Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/kernel/residual.c Wed Feb 25 07:08:01 1998 @@ -7,7 +7,6 @@ * Improved _greatly_ and rewritten by Gabriel Paubert (paubert@iram.es) */ #if 0 -#include #include #include #include @@ -301,10 +300,10 @@ #undef p break; case StartDepFunc: - printk("Start dependant function:\n"); + printk("Start dependent function:\n"); break; case EndDepFunc: - printk("End dependant function\n"); + printk("End dependent function\n"); break; case IOPort: #define p pkt->S8_Pack 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 13 00:18:13 1998 +++ new/linux/arch/ppc/kernel/time.c Sat Feb 21 03:28:21 1998 @@ -6,7 +6,6 @@ * Paul Mackerras' version and mine for PReP and Pmac. */ -#include #include #include #include diff -ur --new-file old/linux/arch/ppc/mm/extable.c new/linux/arch/ppc/mm/extable.c --- old/linux/arch/ppc/mm/extable.c Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/mm/extable.c Sat Feb 21 03:28:21 1998 @@ -4,7 +4,6 @@ * from linux/arch/i386/mm/extable.c */ -#include #include #include diff -ur --new-file old/linux/arch/ppc/pmac_defconfig new/linux/arch/ppc/pmac_defconfig --- old/linux/arch/ppc/pmac_defconfig Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/pmac_defconfig Thu Mar 12 00:13:49 1998 @@ -19,7 +19,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_MODULES=y # CONFIG_MODVERSIONS is not set -CONFIG_KERNELD=y +CONFIG_KMOD=y CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y diff -ur --new-file old/linux/arch/ppc/prep_defconfig new/linux/arch/ppc/prep_defconfig --- old/linux/arch/ppc/prep_defconfig Tue Jan 13 00:18:13 1998 +++ new/linux/arch/ppc/prep_defconfig Thu Mar 12 00:13:49 1998 @@ -19,7 +19,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y -CONFIG_KERNELD=y +CONFIG_KMOD=y CONFIG_PCI=y # CONFIG_PCI_OPTIMIZE is not set CONFIG_NET=y diff -ur --new-file old/linux/arch/sparc/ap1000/apmmu.c new/linux/arch/sparc/ap1000/apmmu.c --- old/linux/arch/sparc/ap1000/apmmu.c Sun Jan 26 11:07:06 1997 +++ new/linux/arch/sparc/ap1000/apmmu.c Sat Feb 21 03:28:22 1998 @@ -11,7 +11,6 @@ * based on srmmu.c */ -#include #include #include #include @@ -593,7 +592,7 @@ static unsigned long apmmu_alloc_kernel_stack(struct task_struct *tsk) { - unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0); + unsigned long kstk = __get_free_pages(GFP_KERNEL, 1); if(!kstk) kstk = (unsigned long) vmalloc(PAGE_SIZE << 1); diff -ur --new-file old/linux/arch/sparc/ap1000/bnet.c new/linux/arch/sparc/ap1000/bnet.c --- old/linux/arch/sparc/ap1000/bnet.c Wed May 14 07:41:03 1997 +++ new/linux/arch/sparc/ap1000/bnet.c Sat Feb 21 03:28:22 1998 @@ -8,7 +8,6 @@ /* routines to control the AP1000 bif interface. This is the interface used to talk to the front end processor */ -#include #include #include #include @@ -584,7 +583,7 @@ if (q->req.type == REQ_IP) { struct sk_buff *skb = (struct sk_buff *)q->data; write_bif(skb->data,q->data_size,1,1); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } else { write_bif(q->data,q->data_size,1,1); if (!(q->flags & BIF_NOCOPY)) @@ -718,7 +717,7 @@ q = (struct bif_queue *)kmalloc(sizeof(*q), GFP_ATOMIC); if (!q) { /* yikes! */ - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return(-ENOMEM); } @@ -1021,7 +1020,7 @@ } if (skb_out) { - dev_kfree_skb(skb_out, FREE_WRITE); + dev_kfree_skb(skb_out); skb_out = NULL; } diff -ur --new-file old/linux/arch/sparc/ap1000/msc.c new/linux/arch/sparc/ap1000/msc.c --- old/linux/arch/sparc/ap1000/msc.c Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/ap1000/msc.c Sat Feb 21 03:28:22 1998 @@ -10,7 +10,6 @@ * and Memory Controller (MC+). * */ -#include #define _APLIB_ #include #include @@ -237,7 +236,7 @@ MSC_OUT(MSC_SQRAM + i * 8, -1); if (!qof_base) { - qof_base = (struct qof_elt *) __get_free_pages(GFP_ATOMIC, QOF_ORDER, 0); + qof_base = (struct qof_elt *) __get_free_pages(GFP_ATOMIC, QOF_ORDER); for (i = MAP_NR(qof_base); i <= MAP_NR(((char*)qof_base)+QOF_SIZE-1);++i) set_bit(PG_reserved, &mem_map[i].flags); } @@ -285,7 +284,7 @@ if (!system_ringbuf.ringbuf) { system_ringbuf.ringbuf = - (void *)__get_free_pages(GFP_ATOMIC,SYSTEM_RINGBUF_ORDER,0); + (void *)__get_free_pages(GFP_ATOMIC,SYSTEM_RINGBUF_ORDER); for (i=MAP_NR(system_ringbuf.ringbuf); i<=MAP_NR(system_ringbuf.ringbuf+SYSTEM_RINGBUF_SIZE-1);i++) set_bit(PG_reserved, &mem_map[i].flags); @@ -294,7 +293,7 @@ if (!dummy_ringbuf.ringbuf) { dummy_ringbuf.ringbuf = - (void *)__get_free_pages(GFP_ATOMIC,DUMMY_RINGBUF_ORDER,0); + (void *)__get_free_pages(GFP_ATOMIC,DUMMY_RINGBUF_ORDER); for (i=MAP_NR(dummy_ringbuf.ringbuf); i<=MAP_NR(dummy_ringbuf.ringbuf+DUMMY_RINGBUF_SIZE-1);i++) set_bit(PG_reserved, &mem_map[i].flags); diff -ur --new-file old/linux/arch/sparc/ap1000/timer.c new/linux/arch/sparc/ap1000/timer.c --- old/linux/arch/sparc/ap1000/timer.c Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/ap1000/timer.c Sat Feb 21 03:28:22 1998 @@ -7,6 +7,7 @@ */ /* routines to control the AP1000 timer chip */ +#include /* for CONFIG_PROFILE */ #include #include #include diff -ur --new-file old/linux/arch/sparc/ap1000/tnet.c new/linux/arch/sparc/ap1000/tnet.c --- old/linux/arch/sparc/ap1000/tnet.c Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/ap1000/tnet.c Thu Feb 12 01:16:43 1998 @@ -578,7 +578,7 @@ static void free_skb(struct sk_buff *skb, int op) { - dev_kfree_skb(skb,op); + dev_kfree_skb(skb); } void tnet_send_ip(int cid,struct sk_buff *skb) @@ -596,11 +596,10 @@ int *info = (int *)skb->data; /* re-use the header */ info[0] = (int)data; info[1] = size; - info[2] = tnet_add_completion(free_skb,(int)skb,(int)FREE_WRITE); + info[2] = tnet_add_completion(free_skb, (int)skb, 0); tnet_send(cid,TNET_IP,info,sizeof(int)*3,0,0); } else { - flag = tnet_add_completion(free_skb, - (int)skb,(int)FREE_WRITE); + flag = tnet_add_completion(free_skb, (int)skb, 0); tnet_send(cid,TNET_IP_SMALL,data,size,0,flag); tnet_stats.small_packets_sent++; } diff -ur --new-file old/linux/arch/sparc/config.in new/linux/arch/sparc/config.in --- old/linux/arch/sparc/config.in Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/config.in Tue Mar 10 23:43:13 1998 @@ -14,7 +14,7 @@ bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD + bool 'Kernel module loader' CONFIG_KMOD fi endmenu @@ -110,7 +110,7 @@ dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR fi dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI diff -ur --new-file old/linux/arch/sparc/defconfig new/linux/arch/sparc/defconfig --- old/linux/arch/sparc/defconfig Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/defconfig Tue Mar 10 23:43:13 1998 @@ -12,7 +12,7 @@ # CONFIG_MODULES=y CONFIG_MODVERSIONS=y -CONFIG_KERNELD=y +CONFIG_KMOD=y # # General setup diff -ur --new-file old/linux/arch/sparc/kernel/init_task.c new/linux/arch/sparc/kernel/init_task.c --- old/linux/arch/sparc/kernel/init_task.c Wed May 14 07:41:03 1997 +++ new/linux/arch/sparc/kernel/init_task.c Tue Mar 10 22:28:59 1998 @@ -6,6 +6,7 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; +static struct files * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -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 Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/kernel/irq.c Mon Feb 9 22:31:00 1998 @@ -41,10 +41,6 @@ #include #include -#ifdef __SMP_PROF__ -extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]; -#endif - /* * Dave Redman (djhr@tadpole.co.uk) * @@ -136,109 +132,6 @@ } return len; } - -#ifdef __SMP_PROF__ - -static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},}; - -extern unsigned int prof_multiplier[NR_CPUS]; -extern unsigned int prof_counter[NR_CPUS]; - -int get_smp_prof_list(char *buf) { - int i,j, len = 0; - struct irqaction * action; - unsigned long sum_spins = 0; - unsigned long sum_spins_syscall = 0; - unsigned long sum_spins_sys_idle = 0; - unsigned long sum_smp_idle_count = 0; - unsigned long sum_local_timer_ticks = 0; - - for (i=0;ihandler) - continue; - len += sprintf(buf+len, "%3d: %10d ", - i, kstat.interrupts[i]); - for (j=0;jflags & SA_INTERRUPT) ? '+' : ' ', - action->name); - for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ",%s %s", - (action->flags & SA_INTERRUPT) ? " +" : "", - action->name); - } - len += sprintf(buf+len, "\n"); - } - len+=sprintf(buf+len, "LCK: %10lu", - sum_spins); - - for (i=0;iflags |= PF_PTRACED; 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); } send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); @@ -851,6 +854,7 @@ } case PTRACE_SUNDETACH: { /* detach a process that was attached. */ + unsigned long flags; if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); goto out; @@ -858,9 +862,11 @@ child->flags &= ~(PF_PTRACED|PF_TRACESYS); wake_up_process(child); child->exit_code = data; + write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); pt_succ_return(regs, 0); goto out; } 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 Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/kernel/smp.c Sat Feb 21 03:28:22 1998 @@ -3,6 +3,7 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ +#include /* for CONFIG_PROFILE */ #include #include @@ -66,16 +67,6 @@ struct klock_info klock_info = { KLOCK_CLEAR, 0 }; volatile unsigned long ipi_count; -#ifdef __SMP_PROF__ -volatile unsigned long smp_spins[NR_CPUS]={0}; -volatile unsigned long smp_spins_syscall[NR_CPUS]={0}; -volatile unsigned long smp_spins_syscall_cur[NR_CPUS]={0}; -volatile unsigned long smp_spins_sys_idle[NR_CPUS]={0}; -volatile unsigned long smp_idle_count[1+NR_CPUS]={0,}; -#endif -#if defined (__SMP_PROF__) -volatile unsigned long smp_idle_map=0; -#endif volatile int smp_process_available=0; @@ -605,8 +596,6 @@ #endif -volatile unsigned long smp_local_timer_ticks[1+NR_CPUS]={0,}; - unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; @@ -645,9 +634,6 @@ } prof_counter[cpu] = prof_multiplier[cpu]; } -#ifdef __SMP_PROF__ - smp_local_timer_ticks[cpu]++; -#endif } extern unsigned int lvl14_resolution; 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 Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/kernel/sparc_ksyms.c Wed Mar 18 06:15:40 1998 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -271,3 +272,7 @@ EXPORT_SYMBOL_DOT(umul); EXPORT_SYMBOL_DOT(div); EXPORT_SYMBOL_DOT(udiv); + +#if CONFIG_PCI +EXPORT_SYMBOL(pci_devices); +#endif 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 Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/mm/init.c Thu Mar 12 19:56:00 1998 @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_INITRD #include #endif @@ -172,9 +173,6 @@ struct cache_palias *sparc_aliases; -extern int min_free_pages; -extern int free_pages_low; -extern int free_pages_high; extern void srmmu_frob_mem_map(unsigned long); int physmem_mapped_contig = 1; @@ -265,11 +263,11 @@ initpages << (PAGE_SHIFT-10), PAGE_OFFSET, end_mem); - min_free_pages = nr_free_pages >> 7; - if(min_free_pages < 16) - min_free_pages = 16; - free_pages_low = min_free_pages + (min_free_pages >> 1); - free_pages_high = min_free_pages + min_free_pages; + 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; } void free_initmem (void) 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 Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc/mm/srmmu.c Fri Feb 27 20:01:52 1998 @@ -904,7 +904,7 @@ */ struct task_struct *srmmu_alloc_task_struct(void) { - return (struct task_struct *) __get_free_pages(GFP_KERNEL, 1, 0); + return (struct task_struct *) __get_free_pages(GFP_KERNEL, 1); } static void srmmu_free_task_struct(struct task_struct *tsk) @@ -2101,8 +2101,8 @@ { if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) { struct vm_area_struct *vmaring; - struct dentry *dentry; - struct inode *inode = NULL; + struct file *file; + struct inode *inode; unsigned long flags, offset, vaddr, start; int alias_found = 0; pgd_t *pgdp; @@ -2111,11 +2111,10 @@ save_and_cli(flags); - dentry = vma->vm_dentry; - if(dentry) - inode = dentry->d_inode; - if (!inode) + file = vma->vm_file; + if (!file) goto done; + inode = file->f_dentry->d_inode; offset = (address & PAGE_MASK) - vma->vm_start; vmaring = inode->i_mmap; do { 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 Thu Jul 31 22:09:17 1997 +++ new/linux/arch/sparc/mm/sun4c.c Sat Jan 17 05:38:57 1998 @@ -1185,7 +1185,7 @@ unsigned long addr, pages; int entry; - pages = __get_free_pages(GFP_KERNEL, 1, 0); + pages = __get_free_pages(GFP_KERNEL, 1); if(!pages) return (struct task_struct *) 0; diff -ur --new-file old/linux/arch/sparc64/config.in new/linux/arch/sparc64/config.in --- old/linux/arch/sparc64/config.in Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc64/config.in Tue Mar 10 23:43:13 1998 @@ -14,7 +14,7 @@ bool 'Enable loadable module support' CONFIG_MODULES if [ "$CONFIG_MODULES" = "y" ]; then bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS - bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD + bool 'Kernel module loader' CONFIG_KMOD fi endmenu @@ -138,7 +138,7 @@ dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR fi dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI @@ -158,7 +158,7 @@ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y - dep_tristate ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N + bool ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8 fi diff -ur --new-file old/linux/arch/sparc64/defconfig new/linux/arch/sparc64/defconfig --- old/linux/arch/sparc64/defconfig Tue Jan 13 00:15:43 1998 +++ new/linux/arch/sparc64/defconfig Thu Mar 12 00:13:49 1998 @@ -12,7 +12,7 @@ # CONFIG_MODULES=y CONFIG_MODVERSIONS=y -CONFIG_KERNELD=y +CONFIG_KMOD=y # # General setup diff -ur --new-file old/linux/arch/sparc64/kernel/init_task.c new/linux/arch/sparc64/kernel/init_task.c --- old/linux/arch/sparc64/kernel/init_task.c Fri May 16 01:48:02 1997 +++ new/linux/arch/sparc64/kernel/init_task.c Tue Mar 10 22:28:59 1998 @@ -6,6 +6,7 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; +static struct files * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -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 Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/kernel/traps.c Thu Mar 12 19:33:21 1998 @@ -26,8 +26,8 @@ #include #include #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif /* #define SYSCALL_TRACING */ @@ -327,7 +327,7 @@ case (2 << 14): /* unfinished_FPop */ case (3 << 14): /* unimplemented_FPop */ #ifdef CONFIG_MATHEMU_MODULE -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (!handle_mathemu) request_module("math-emu"); #endif 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 Jan 13 00:15:44 1998 +++ new/linux/arch/sparc64/mm/init.c Thu Mar 12 19:56:00 1998 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -265,7 +266,7 @@ ((dvma_pages_current_offset + len) > (1 << 16))) { struct linux_sbus *sbus; unsigned long *iopte; - unsigned long newpages = __get_free_pages(GFP_KERNEL, 3, 0); + unsigned long newpages = __get_free_pages(GFP_KERNEL, 3); int i; if(!newpages) @@ -864,10 +865,6 @@ return device_scan (PAGE_ALIGN (start_mem)); } -extern int min_free_pages; -extern int free_pages_low; -extern int free_pages_high; - __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem)) { unsigned long addr, tmp2 = 0; @@ -946,11 +943,11 @@ initpages << (PAGE_SHIFT-10), PAGE_OFFSET, end_mem); - min_free_pages = nr_free_pages >> 7; - if(min_free_pages < 16) - min_free_pages = 16; - free_pages_low = min_free_pages + (min_free_pages >> 1); - free_pages_high = min_free_pages + min_free_pages; + freepages.low = nr_free_pages >> 7; + if(freepages.low < 16) + freepages.low = 16; + freepages.low = freepages.low + (freepages.low >> 1); + freepages.high = freepages.low + freepages.low; } void free_initmem (void) diff -ur --new-file old/linux/drivers/acorn/README new/linux/drivers/acorn/README --- old/linux/drivers/acorn/README Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/README Tue Feb 17 00:49:47 1998 @@ -0,0 +1,3 @@ +Drivers for the ACORN "podule" ARM specific bus. + + diff -ur --new-file old/linux/drivers/acorn/block/Config.in new/linux/drivers/acorn/block/Config.in --- old/linux/drivers/acorn/block/Config.in Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/block/Config.in Mon Feb 16 22:46:44 1998 @@ -0,0 +1,21 @@ +# +# Block device driver configuration +# +mainmenu_option next_comment +comment 'Acorn-Specific floppy, IDE, and other block devices' + +tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD +bool ' Support expansion card IDE interfaces' CONFIG_BLK_DEV_IDE_CARDS +if [ "$CONFIG_BLK_DEV_IDE_CARDS" = "y" ]; then + dep_tristate ' ICS IDE interface support' CONFIG_BLK_DEV_IDE_ICSIDE $CONFIG_BLK_DEV_IDE + dep_tristate ' RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_BLK_DEV_IDE +fi + +tristate 'MFM harddisk support' CONFIG_BLK_DEV_MFM +if [ "$CONFIG_BLK_DEV_MFM" != "n" ]; then + bool ' Autodetect hard drive geometry' CONFIG_BLK_DEV_MFM_AUTODETECT +fi + +bool 'ADFS partition support' CONFIG_BLK_DEV_PART + +endmenu diff -ur --new-file old/linux/drivers/acorn/block/Makefile new/linux/drivers/acorn/block/Makefile --- old/linux/drivers/acorn/block/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/block/Makefile Mon Feb 16 22:49:36 1998 @@ -0,0 +1,66 @@ +# +# Makefile for the Acorn block device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now inherited from the +# parent makefile. +# + +L_TARGET := acorn-block.a +L_OBJS := +M_OBJS := +MOD_LIST_NAME := ACORN_BLOCK_MODULES + +ifeq ($(CONFIG_ARCH_ARC),y) + ifeq ($(CONFIG_BLK_DEV_FD),y) + L_OBJS += fd1772.o fd1772dma.o + else + ifeq ($(CONFIG_BLK_DEV_FD),m) + M_OBJS += fd1772_mod.o + endif + endif +endif + +ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),y) + L_OBJS += ide-ics.o +else + ifeq ($(CONFIG_BLK_DEV_IDE_ICSIDE),m) + M_OBJS += ide-ics.o + endif +endif + +ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),y) + L_OBJS += ide-rapide.o +else + ifeq ($(CONFIG_BLK_DEV_IDE_RAPIDE),m) + M_OBJS += ide-rapide.o + endif +endif + +ifeq ($(CONFIG_BLK_DEV_MFM),y) + L_OBJS += mfmhd.o mfm.o +else + ifeq ($(CONFIG_BLK_DEV_MFM),m) + M_OBJS += mfmhd_mod.o + endif +endif + +include $(TOPDIR)/Rules.make + +fd1772_mod.o: $(FLOPPY) + $(LD) -r -o $@ $(FLOPPY) + +mfmhd_mod.o: mfmhd.o mfm.o + $(LD) -r -o $@ mfmhd.o mfm.o + +%.o: %.S +ifndef $(CONFIG_BINUTILS_NEW) + $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.s + $(CC) $(CFLAGS) -c -o $@ ..tmp.s + $(RM) ..tmp.s +else + $(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $< +endif diff -ur --new-file old/linux/drivers/acorn/block/fd1772.c new/linux/drivers/acorn/block/fd1772.c --- old/linux/drivers/acorn/block/fd1772.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/block/fd1772.c Sat Feb 21 22:25:15 1998 @@ -0,0 +1,1669 @@ +/* + * linux/kernel/arch/arm/drivers/block/fd1772.c + * Based on ataflop.c in the m68k Linux + * Copyright (C) 1993 Greg Harp + * Atari Support by Bjoern Brauel, Roman Hodek + * Archimedes Support by Dave Gilbert (gilbertd@cs.man.ac.uk) + * + * Big cleanup Sep 11..14 1994 Roman Hodek: + * - Driver now works interrupt driven + * - Support for two drives; should work, but I cannot test that :-( + * - Reading is done in whole tracks and buffered to speed up things + * - Disk change detection and drive deselecting after motor-off + * similar to TOS + * - Autodetection of disk format (DD/HD); untested yet, because I + * don't have an HD drive :-( + * + * Fixes Nov 13 1994 Martin Schaller: + * - Autodetection works now + * - Support for 5 1/4" disks + * - Removed drive type (unknown on atari) + * - Do seeks with 8 Mhz + * + * Changes by Andreas Schwab: + * - After errors in multiple read mode try again reading single sectors + * (Feb 1995): + * - Clean up error handling + * - Set blk_size for proper size checking + * - Initialize track register when testing presence of floppy + * - Implement some ioctl's + * + * Changes by Torsten Lang: + * - When probing the floppies we should add the FDC1772CMDADD_H flag since + * the FDC1772 will otherwise wait forever when no disk is inserted... + * + * Things left to do: + * - Formatting + * - Maybe a better strategy for disk change detection (does anyone + * know one?) + * - There are some strange problems left: The strangest one is + * that, at least on my TT (4+4MB), the first 2 Bytes of the last + * page of the TT-Ram (!) change their contents (some bits get + * set) while a floppy DMA is going on. But there are no accesses + * to these memory locations from the kernel... (I tested that by + * making the page read-only). I cannot explain what's going on... + * - Sometimes the drive-change-detection stops to work. The + * function is still called, but the WP bit always reads as 0... + * Maybe a problem with the status reg mode or a timing problem. + * Note 10/12/94: The change detection now seems to work reliably. + * There is no proof, but I've seen no hang for a long time... + * + * ARCHIMEDES changes: (gilbertd@cs.man.ac.uk) + * 26/12/95 - Changed all names starting with FDC to FDC1772 + * Removed all references to clock speed of FDC - we're stuck with 8MHz + * Modified disk_type structure to remove HD formats + * + * 7/ 1/96 - Wrote FIQ code, removed most remaining atariisms + * + * 13/ 1/96 - Well I think its read a single sector; but there is a problem + * fd_rwsec_done which is called in FIQ mode starts another transfer + * off (in fd_rwsec) while still in FIQ mode. Because its still in + * FIQ mode it can't service the DMA and loses data. So need to + * heavily restructure. + * 14/ 1/96 - Found that the definitions of the register numbers of the + * FDC were multiplied by 2 in the header for the 16bit words + * of the atari so half the writes were going in the wrong place. + * Also realised that the FIQ entry didn't make any attempt to + * preserve registers or return correctly; now in assembler. + * + * 11/ 2/96 - Hmm - doesn't work on real machine. Auto detect doesn't + * and hacking that past seems to wait forever - check motor + * being turned on. + * + * 17/ 2/96 - still having problems - forcing track to -1 when selecting + * new drives seems to allow it to read first few sectors + * but then we get solid hangs at apparently random places + * which change depending what is happening. + * + * 9/ 3/96 - Fiddled a lot of stuff around to move to kernel 1.3.35 + * A lot of fiddling in DMA stuff. Having problems with it + * constnatly thinking its timeing out. Ah - its timeout + * was set to (6*HZ) rather than jiffies+(6*HZ). Now giving + * duff data! + * + * 5/ 4/96 - Made it use the new IOC_ macros rather than *ioc + * Hmm - giving unexpected FIQ and then timeouts + * 18/ 8/96 - Ran through indent -kr -i8 + * Some changes to disc change detect; don't know how well it + * works. + * 24/ 8/96 - Put all the track buffering code back in from the atari + * code - I wonder if it will still work... No :-) + * Still works if I turn off track buffering. + * 25/ 8/96 - Changed the timer expires that I'd added back to be + * jiffies + ....; and it all sprang to life! Got 2.8K/sec + * off a cp -r of a 679K disc (showed 94% cpu usage!) + * (PC gets 14.3K/sec - 0% CPU!) Hmm - hard drive corrupt! + * Also perhaps that compile was with cache off. + * changed cli in fd_readtrack_check to cliIF + * changed vmallocs to kmalloc (whats the difference!!) + * Removed the busy wait loop in do_fd_request and replaced + * by a routine on tq_immediate; only 11% cpu on a dd off the + * raw disc - but the speed is the same. + * 1/ 9/96 - Idea (failed!) - set the 'disable spin-up seqeunce' + * when we read the track if we know the motor is on; didn't + * help - perhaps we have to do it in stepping as well. + * Nope. Still doesn't help. + * Hmm - what seems to be happening is that fd_readtrack_check + * is never getting called. Its job is to terminate the read + * just after we think we should have got the data; otherwise + * the fdc takes 1 second to timeout; which is what's happening + * Now I can see 'readtrack_timer' being set (which should do the + * call); but it never seems to be called - hmm! + * OK - I've moved the check to my tq_immediate code - + * and it WORKS! 13.95K/second at 19% CPU. + * I wish I knew why that timer didn't work..... + * + * 16/11/96 - Fiddled and frigged for 2.0.18 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR FLOPPY_MAJOR +#define FLOPPY_DMA 0 +#include "blk.h" + +/* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with + * little additional rework in this file). But I'm not yet sure if + * some other code depends on the number of floppies... (It is defined + * in a public header!) + */ +#if 0 +#undef FD_MAX_UNITS +#define FD_MAX_UNITS 2 +#endif + +/* Ditto worries for Arc - DAG */ +#define FD_MAX_UNITS 4 +#define TRACKBUFFER 0 +/*#define DEBUG*/ + +#ifdef DEBUG +#define DPRINT(a) printk a +#else +#define DPRINT(a) +#endif + +/* Disk types: DD */ +static struct archy_disk_type { + const char *name; + unsigned spt; /* sectors per track */ + unsigned blocks; /* total number of blocks */ + unsigned stretch; /* track doubling ? */ +} disk_type[] = { + + { "d360", 9, 720, 0 }, /* 360kB diskette */ + { "D360", 9, 720, 1 }, /* 360kb in 720kb drive */ + { "D720", 9, 1440, 0 }, /* 720kb diskette (DD) */ + /*{ "D820", 10,1640, 0}, *//* DD disk with 82 tracks/10 sectors + - DAG - can't see how type detect can distinguish this + from 720K until it reads block 4 by which time its too late! */ +}; + +#define NUM_DISK_TYPES (sizeof(disk_type)/sizeof(*disk_type)) + +/* + * Maximum disk size (in kilobytes). This default is used whenever the + * current disk size is unknown. + */ +#define MAX_DISK_SIZE 720 + +static int floppy_sizes[256]; +static int floppy_blocksizes[256] = {0,}; + +/* current info on each unit */ +static struct archy_floppy_struct { + int connected; /* !=0 : drive is connected */ + int autoprobe; /* !=0 : do autoprobe */ + + struct archy_disk_type *disktype; /* current type of disk */ + + int track; /* current head position or -1 + * if unknown */ + unsigned int steprate; /* steprate setting */ + unsigned int wpstat; /* current state of WP signal + * (for disk change detection) */ +} unit[FD_MAX_UNITS]; + +/* DAG: On Arc we spin on a flag being cleared by fdc1772_comendhandler which + is an assembler routine */ +extern void fdc1772_comendhandler(void); /* Actually doens't have these parameters - see fd1772.S */ +extern volatile int fdc1772_comendstatus; +extern volatile int fdc1772_fdc_int_done; + +#define FDC1772BASE ((0x210000>>2)|0x80000000) + +#define FDC1772_READ(reg) inb(FDC1772BASE+(reg/2)) + +/* DAG: You wouldn't be silly to ask why FDC1772_WRITE is a function rather + than the #def below - well simple - the #def won't compile - and I + don't understand why (__outwc not defined) */ +/* NOTE: Reg is 0,2,4,6 as opposed to 0,1,2,3 or 0,4,8,12 to keep compatibility + with the ST version of fd1772.h */ +/*#define FDC1772_WRITE(reg,val) outw(val,(reg+FDC1772BASE)); */ +void FDC1772_WRITE(int reg, unsigned char val) +{ + if (reg == FDC1772REG_CMD) { + DPRINT(("FDC1772_WRITE new command 0x%x @ %d\n", val,jiffies)); + if (fdc1772_fdc_int_done) { + DPRINT(("FDC1772_WRITE: Hmm fdc1772_fdc_int_done true - resetting\n")); + fdc1772_fdc_int_done = 0; + }; + }; + outb(val, (reg / 2) + FDC1772BASE); +}; + +#define MAX_SECTORS 22 + +unsigned char *DMABuffer; /* buffer for writes */ +/*static unsigned long PhysDMABuffer; *//* physical address */ +/* DAG: On Arc we just go straight for the DMA buffer */ +#define PhysDMABuffer DMABuffer + +#ifdef TRACKBUFFER +unsigned char *TrackBuffer; /* buffer for reads */ +#define PhysTrackBuffer TrackBuffer /* physical address */ +static int BufferDrive, BufferSide, BufferTrack; +static int read_track; /* non-zero if we are reading whole tracks */ + +#define SECTOR_BUFFER(sec) (TrackBuffer + ((sec)-1)*512) +#define IS_BUFFERED(drive,side,track) \ + (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track)) +#endif + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +static int SelectedDrive = 0; +static int ReqCmd, ReqBlock; +static int ReqSide, ReqTrack, ReqSector, ReqCnt; +static int HeadSettleFlag = 0; +static unsigned char *ReqData, *ReqBuffer; +static int MotorOn = 0, MotorOffTrys; + +/* Synchronization of FDC1772 access. */ +static volatile int fdc_busy = 0; +static struct wait_queue *fdc_wait = NULL; + + +static unsigned int changed_floppies = 0xff, fake_change = 0; +#define CHECK_CHANGE_DELAY HZ/2 + +/* DAG - increased to 30*HZ - not sure if this is the correct thing to do */ +#define FD_MOTOR_OFF_DELAY (10*HZ) +#define FD_MOTOR_OFF_MAXTRY (10*20) + +#define FLOPPY_TIMEOUT (6*HZ) +#define RECALIBRATE_ERRORS 4 /* After this many errors the drive + * will be recalibrated. */ +#define MAX_ERRORS 8 /* After this many errors the driver + * will give up. */ + + +#define START_MOTOR_OFF_TIMER(delay) \ + do { \ + motor_off_timer.expires = jiffies + (delay); \ + add_timer( &motor_off_timer ); \ + MotorOffTrys = 0; \ + } while(0) + +#define START_CHECK_CHANGE_TIMER(delay) \ + do { \ + timer_table[FLOPPY_TIMER].expires = jiffies + (delay); \ + timer_active |= (1 << FLOPPY_TIMER); \ + } while(0) + +#define START_TIMEOUT() \ + do { \ + del_timer( &timeout_timer ); \ + timeout_timer.expires = jiffies + FLOPPY_TIMEOUT; \ + add_timer( &timeout_timer ); \ + } while(0) + +#define STOP_TIMEOUT() \ + do { \ + del_timer( &timeout_timer ); \ + } while(0) + +#define ENABLE_IRQ() enable_irq(FIQ_FD1772+64); + +#define DISABLE_IRQ() disable_irq(FIQ_FD1772+64); + +static void fd1772_checkint(void); + +struct tq_struct fd1772_tq = +{ 0,0, (void *)fd1772_checkint, 0 }; +/* + * The driver is trying to determine the correct media format + * while Probing is set. fd_rwsec_done() clears it after a + * successful access. + */ +static int Probing = 0; + +/* This flag is set when a dummy seek is necesary to make the WP + * status bit accessible. + */ +static int NeedSeek = 0; + + +/***************************** Prototypes *****************************/ + +static void fd_select_side(int side); +static void fd_select_drive(int drive); +static void fd_deselect(void); +static void fd_motor_off_timer(unsigned long dummy); +static void check_change(void); +static __inline__ void set_head_settle_flag(void); +static __inline__ int get_head_settle_flag(void); +static void floppy_irqconsequencehandler(void); +static void fd_error(void); +static void do_fd_action(int drive); +static void fd_calibrate(void); +static void fd_calibrate_done(int status); +static void fd_seek(void); +static void fd_seek_done(int status); +static void fd_rwsec(void); +#ifdef TRACKBUFFER +static void fd_readtrack_check( unsigned long dummy ); +#endif +static void fd_rwsec_done(int status); +static void fd_times_out(unsigned long dummy); +static void finish_fdc(void); +static void finish_fdc_done(int dummy); +static void floppy_off(unsigned int nr); +static __inline__ void copy_buffer(void *from, void *to); +static void setup_req_params(int drive); +static void redo_fd_request(void); +static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int + cmd, unsigned long param); +static void fd_probe(int drive); +static int fd_test_drive_present(int drive); +static void config_types(void); +static int floppy_open(struct inode *inode, struct file *filp); +static void floppy_release(struct inode *inode, struct file *filp); + +/************************* End of Prototypes **************************/ + +static struct timer_list motor_off_timer = +{NULL, NULL, 0, 0, fd_motor_off_timer}; +#ifdef TRACKBUFFER +static struct timer_list readtrack_timer = + { NULL, NULL, 0, 0, fd_readtrack_check }; +#endif +static struct timer_list timeout_timer = +{NULL, NULL, 0, 0, fd_times_out}; + +/* DAG: Haven't got a clue what this is? */ +int stdma_islocked(void) +{ + return 0; +}; + +/* Select the side to use. */ + +static void fd_select_side(int side) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + oldlatch_aupdate(LATCHA_SIDESEL, side ? 0 : LATCHA_SIDESEL); + restore_flags(flags); +} + + +/* Select a drive, update the FDC1772's track register + */ + +static void fd_select_drive(int drive) +{ + unsigned long flags; + +#ifdef DEBUG + printk("fd_select_drive:%d\n", drive); +#endif + /* Hmm - nowhere do we seem to turn the motor on - I'm going to do it here! */ + oldlatch_aupdate(LATCHA_MOTOR | LATCHA_INUSE, 0); + + if (drive == SelectedDrive) + return; + + save_flags(flags); + cli(); + oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive)); + restore_flags(flags); + + /* restore track register to saved value */ + FDC1772_WRITE(FDC1772REG_TRACK, unit[drive].track); + udelay(25); + + SelectedDrive = drive; +} + + +/* Deselect both drives. */ + +static void fd_deselect(void) +{ + unsigned long flags; + + DPRINT(("fd_deselect\n")); + + save_flags(flags); + cli(); + oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE); + restore_flags(flags); + + SelectedDrive = -1; +} + + +/* This timer function deselects the drives when the FDC1772 switched the + * motor off. The deselection cannot happen earlier because the FDC1772 + * counts the index signals, which arrive only if one drive is selected. + */ + +static void fd_motor_off_timer(unsigned long dummy) +{ + unsigned long flags; + unsigned char status; + int delay; + + del_timer(&motor_off_timer); + + if (SelectedDrive < 0) + /* no drive selected, needn't deselect anyone */ + return; + + save_flags(flags); + cli(); + + if (fdc_busy) /* was stdma_islocked */ + goto retry; + + status = FDC1772_READ(FDC1772REG_STATUS); + + if (!(status & 0x80)) { + /* motor already turned off by FDC1772 -> deselect drives */ + /* In actual fact its this deselection which turns the motor off on the + Arc, since the motor control is actually on Latch A */ + DPRINT(("fdc1772: deselecting in fd_motor_off_timer\n")); + fd_deselect(); + MotorOn = 0; + restore_flags(flags); + return; + } + /* not yet off, try again */ + + retry: + restore_flags(flags); + /* Test again later; if tested too often, it seems there is no disk + * in the drive and the FDC1772 will leave the motor on forever (or, + * at least until a disk is inserted). So we'll test only twice + * per second from then on... + */ + delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ? + (++MotorOffTrys, HZ / 20) : HZ / 2; + START_MOTOR_OFF_TIMER(delay); +} + + +/* This function is repeatedly called to detect disk changes (as good + * as possible) and keep track of the current state of the write protection. + */ + +static void check_change(void) +{ + static int drive = 0; + + unsigned long flags; + int stat; + + if (fdc_busy) + return; /* Don't start poking about if the fdc is busy */ + + return; /* lets just forget it for the mo DAG */ + + if (++drive > 1 || !unit[drive].connected) + drive = 0; + + save_flags(flags); + cli(); + + if (!stdma_islocked()) { + stat = !!(FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_WPROT); + + /* The idea here is that if the write protect line has changed then + the disc must have changed */ + if (stat != unit[drive].wpstat) { + DPRINT(("wpstat[%d] = %d\n", drive, stat)); + unit[drive].wpstat = stat; + set_bit(drive, &changed_floppies); + } + } + restore_flags(flags); + + START_CHECK_CHANGE_TIMER(CHECK_CHANGE_DELAY); +} + + +/* Handling of the Head Settling Flag: This flag should be set after each + * seek operation, because we dont't use seeks with verify. + */ + +static __inline__ void set_head_settle_flag(void) +{ + HeadSettleFlag = FDC1772CMDADD_E; +} + +static __inline__ int get_head_settle_flag(void) +{ + int tmp = HeadSettleFlag; + HeadSettleFlag = 0; + return (tmp); +} + + + + +/* General Interrupt Handling */ + +static void (*FloppyIRQHandler) (int status) = NULL; + +static void floppy_irqconsequencehandler(void) +{ + unsigned char status; + void (*handler) (int); + + fdc1772_fdc_int_done = 0; + + handler = FloppyIRQHandler; + FloppyIRQHandler = NULL; + + if (handler) { + nop(); + status = (unsigned char) fdc1772_comendstatus; + DPRINT(("FDC1772 irq, status = %02x handler = %08lx\n", (unsigned int) status, (unsigned long) handler)); + handler(status); + } else { + DPRINT(("FDC1772 irq, no handler status=%02x\n", fdc1772_comendstatus)); + } + DPRINT(("FDC1772 irq: end of floppy_irq\n")); +} + + +/* Error handling: If some error happened, retry some times, then + * recalibrate, then try again, and fail after MAX_ERRORS. + */ + +static void fd_error(void) +{ + printk("FDC1772: fd_error\n"); + /*panic("fd1772: fd_error"); *//* DAG tmp */ + if (!CURRENT) + return; + CURRENT->errors++; + if (CURRENT->errors >= MAX_ERRORS) { + printk("fd%d: too many errors.\n", SelectedDrive); + end_request(0); + } else if (CURRENT->errors == RECALIBRATE_ERRORS) { + printk("fd%d: recalibrating\n", SelectedDrive); + if (SelectedDrive != -1) + unit[SelectedDrive].track = -1; + } + redo_fd_request(); +} + + + +#define SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0) + + +/* do_fd_action() is the general procedure for a fd request: All + * required parameter settings (drive select, side select, track + * position) are checked and set if needed. For each of these + * parameters and the actual reading or writing exist two functions: + * one that starts the setting (or skips it if possible) and one + * callback for the "done" interrupt. Each done func calls the next + * set function to propagate the request down to fd_rwsec_done(). + */ + +static void do_fd_action(int drive) +{ + DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track)); + +#ifdef TRACKBUFFER + repeat: + + if (IS_BUFFERED( drive, ReqSide, ReqTrack )) { + if (ReqCmd == READ) { + copy_buffer( SECTOR_BUFFER(ReqSector), ReqData ); + if (++ReqCnt < CURRENT->current_nr_sectors) { + /* read next sector */ + setup_req_params( drive ); + goto repeat; + } + else { + /* all sectors finished */ + CURRENT->nr_sectors -= CURRENT->current_nr_sectors; + CURRENT->sector += CURRENT->current_nr_sectors; + end_request( 1 ); + redo_fd_request(); + return; + } + } + else { + /* cmd == WRITE, pay attention to track buffer + * consistency! */ + copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) ); + } + } +#endif + + if (SelectedDrive != drive) { + /*unit[drive].track = -1; DAG */ + fd_select_drive(drive); + }; + + + if (unit[drive].track == -1) + fd_calibrate(); + else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch) + fd_seek(); + else + fd_rwsec(); +} + + +/* Seek to track 0 if the current track is unknown */ + +static void fd_calibrate(void) +{ + DPRINT(("fd_calibrate\n")); + if (unit[SelectedDrive].track >= 0) { + fd_calibrate_done(0); + return; + } + DPRINT(("fd_calibrate (after track compare)\n")); + SET_IRQ_HANDLER(fd_calibrate_done); + /* we can't verify, since the speed may be incorrect */ + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate); + + NeedSeek = 1; + MotorOn = 1; + START_TIMEOUT(); + /* wait for IRQ */ +} + + +static void fd_calibrate_done(int status) +{ + DPRINT(("fd_calibrate_done()\n")); + STOP_TIMEOUT(); + + /* set the correct speed now */ + if (status & FDC1772STAT_RECNF) { + printk("fd%d: restore failed\n", SelectedDrive); + fd_error(); + } else { + unit[SelectedDrive].track = 0; + fd_seek(); + } +} + + +/* Seek the drive to the requested track. The drive must have been + * calibrated at some point before this. + */ + +static void fd_seek(void) +{ + unsigned long flags; + DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack, + unit[SelectedDrive].track)); + if (unit[SelectedDrive].track == ReqTrack << + unit[SelectedDrive].disktype->stretch) { + fd_seek_done(0); + return; + } + FDC1772_WRITE(FDC1772REG_DATA, ReqTrack << + unit[SelectedDrive].disktype->stretch); + udelay(25); + save_flags(flags); + cliIF(); + SET_IRQ_HANDLER(fd_seek_done); + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate | + /* DAG */ + (MotorOn?FDC1772CMDADD_H:0)); + + restore_flags(flags); + MotorOn = 1; + set_head_settle_flag(); + START_TIMEOUT(); + /* wait for IRQ */ +} + + +static void fd_seek_done(int status) +{ + DPRINT(("fd_seek_done()\n")); + STOP_TIMEOUT(); + + /* set the correct speed */ + if (status & FDC1772STAT_RECNF) { + printk("fd%d: seek error (to track %d)\n", + SelectedDrive, ReqTrack); + /* we don't know exactly which track we are on now! */ + unit[SelectedDrive].track = -1; + fd_error(); + } else { + unit[SelectedDrive].track = ReqTrack << + unit[SelectedDrive].disktype->stretch; + NeedSeek = 0; + fd_rwsec(); + } +} + + +/* This does the actual reading/writing after positioning the head + * over the correct track. + */ + +#ifdef TRACKBUFFER +static int MultReadInProgress = 0; +#endif + + +static void fd_rwsec(void) +{ + unsigned long paddr, flags; + unsigned int rwflag, old_motoron; + unsigned int track; + + DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n", ReqSector, ReqCmd == WRITE ? 'w' : 'r')); + if (ReqCmd == WRITE) { + /*cache_push( (unsigned long)ReqData, 512 ); */ + paddr = (unsigned long) ReqData; + rwflag = 0x100; + } else { +#ifdef TRACKBUFFER + if (read_track) + paddr = (unsigned long)PhysTrackBuffer; + else + paddr =(unsigned long)PhysDMABuffer; +#else + paddr = (unsigned long)PhysDMABuffer; +#endif + rwflag = 0; + } + + DPRINT(("fd_rwsec() before sidesel rwflag=%d sec=%d trk=%d\n", rwflag, + ReqSector, FDC1772_READ(FDC1772REG_TRACK))); + fd_select_side(ReqSide); + + /*DPRINT(("fd_rwsec() before start sector \n")); */ + /* Start sector of this operation */ +#ifdef TRACKBUFFER + FDC1772_WRITE( FDC1772REG_SECTOR, !read_track ? ReqSector : 1 ); +#else + FDC1772_WRITE( FDC1772REG_SECTOR, ReqSector ); +#endif + + /* Cheat for track if stretch != 0 */ + if (unit[SelectedDrive].disktype->stretch) { + track = FDC1772_READ(FDC1772REG_TRACK); + FDC1772_WRITE(FDC1772REG_TRACK, track >> + unit[SelectedDrive].disktype->stretch); + } + udelay(25); + + DPRINT(("fd_rwsec() before setup DMA \n")); + /* Setup DMA - Heavily modified by DAG */ + save_flags(flags); + cliIF(); + disable_dma(FLOPPY_DMA); + set_dma_mode(FLOPPY_DMA, rwflag ? DMA_MODE_WRITE : DMA_MODE_READ); + set_dma_addr(FLOPPY_DMA, (long) paddr); /* DAG - changed from Atari specific */ +#ifdef TRACKBUFFER + set_dma_count(FLOPPY_DMA,(!read_track ? 1 : unit[SelectedDrive].disktype->spt)*512); +#else + set_dma_count(FLOPPY_DMA, 512); /* Block/sector size - going to have to change */ +#endif + SET_IRQ_HANDLER(fd_rwsec_done); + /* Turn on dma int */ + enable_dma(FLOPPY_DMA); + /* Now give it something to do */ + FDC1772_WRITE(FDC1772REG_CMD, (rwflag ? (FDC1772CMD_WRSEC | FDC1772CMDADD_P) : +#ifdef TRACKBUFFER + (FDC1772CMD_RDSEC | (read_track ? FDC1772CMDADD_M : 0) | + /* Hmm - the idea here is to stop the FDC spinning the disc + up when we know that we already still have it spinning */ + (MotorOn?FDC1772CMDADD_H:0)) +#else + FDC1772CMD_RDSEC +#endif + )); + + restore_flags(flags); + DPRINT(("fd_rwsec() after DMA setup flags=0x%08x\n", flags)); + /*sti(); *//* DAG - Hmm */ + /* Hmm - should do something DAG */ + old_motoron = MotorOn; + MotorOn = 1; + NeedSeek = 1; + + /* wait for interrupt */ + +#ifdef TRACKBUFFER + if (read_track) { + /* If reading a whole track, wait about one disk rotation and + * then check if all sectors are read. The FDC will even + * search for the first non-existant sector and need 1 sec to + * recognise that it isn't present :-( + */ + del_timer( &readtrack_timer ); + readtrack_timer.function = fd_readtrack_check; + readtrack_timer.expires = jiffies + HZ/5 + (old_motoron ? 0 : HZ); + /* 1 rot. + 5 rot.s if motor was off */ + DPRINT(("Setting readtrack_timer to %d @ %d\n",readtrack_timer.expires,jiffies)); + add_timer( &readtrack_timer ); + MultReadInProgress = 1; + } +#endif + + /*DPRINT(("fd_rwsec() before START_TIMEOUT \n")); */ + START_TIMEOUT(); + /*DPRINT(("fd_rwsec() after START_TIMEOUT \n")); */ +} + + +#ifdef TRACKBUFFER + +static void fd_readtrack_check( unsigned long dummy ) + +{ unsigned long flags, addr; + extern unsigned char *fdc1772_dataaddr; + + DPRINT(("fd_readtrack_check @ %d\n",jiffies)); + + save_flags(flags); + cliIF(); + + del_timer( &readtrack_timer ); + + if (!MultReadInProgress) { + /* This prevents a race condition that could arise if the + * interrupt is triggered while the calling of this timer + * callback function takes place. The IRQ function then has + * already cleared 'MultReadInProgress' when control flow + * gets here. + */ + restore_flags(flags); + return; + } + + /* get the current DMA address */ + addr=fdc1772_dataaddr; /* DAG - ? */ + DPRINT(("fd_readtrack_check: addr=%x PhysTrackBuffer=%x\n",addr,PhysTrackBuffer)); + + if (addr >= PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) { + /* already read enough data, force an FDC interrupt to stop + * the read operation + */ + SET_IRQ_HANDLER( NULL ); + restore_flags(flags); + DPRINT(("fd_readtrack_check(): done\n")); + FDC1772_WRITE( FDC1772REG_CMD, FDC1772CMD_FORCI ); + udelay(25); + + /* No error until now -- the FDC would have interrupted + * otherwise! + */ + fd_rwsec_done( 0 ); + } + else { + /* not yet finished, wait another tenth rotation */ + restore_flags(flags); + DPRINT(("fd_readtrack_check(): not yet finished\n")); + readtrack_timer.expires = jiffies + HZ/5/10; + add_timer( &readtrack_timer ); + } +} + +#endif + +static void fd_rwsec_done(int status) +{ + unsigned int track; + + DPRINT(("fd_rwsec_done() status=%d @ %d\n", status,jiffies)); + +#ifdef TRACKBUFFER + if (read_track && !MultReadInProgress) return; + MultReadInProgress = 0; + + STOP_TIMEOUT(); + + if (read_track) + del_timer( &readtrack_timer ); +#endif + + + /* Correct the track if stretch != 0 */ + if (unit[SelectedDrive].disktype->stretch) { + track = FDC1772_READ(FDC1772REG_TRACK); + FDC1772_WRITE(FDC1772REG_TRACK, track << + unit[SelectedDrive].disktype->stretch); + } + if (ReqCmd == WRITE && (status & FDC1772STAT_WPROT)) { + printk("fd%d: is write protected\n", SelectedDrive); + goto err_end; + } + if ((status & FDC1772STAT_RECNF) +#ifdef TRACKBUFFER + /* RECNF is no error after a multiple read when the FDC + * searched for a non-existant sector! + */ + && !(read_track && + FDC1772_READ(FDC1772REG_SECTOR) > unit[SelectedDrive].disktype->spt) +#endif + ) { + if (Probing) { + if (unit[SelectedDrive].disktype > disk_type) { + /* try another disk type */ + unit[SelectedDrive].disktype--; + floppy_sizes[SelectedDrive] + = unit[SelectedDrive].disktype->blocks >> 1; + } else + Probing = 0; + } else { + /* record not found, but not probing. Maybe stretch wrong ? Restart probing */ + if (unit[SelectedDrive].autoprobe) { + unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES - 1; + floppy_sizes[SelectedDrive] + = unit[SelectedDrive].disktype->blocks >> 1; + Probing = 1; + } + } + if (Probing) { + setup_req_params(SelectedDrive); +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + do_fd_action(SelectedDrive); + return; + } + printk("fd%d: sector %d not found (side %d, track %d)\n", + SelectedDrive, FDC1772_READ(FDC1772REG_SECTOR), ReqSide, ReqTrack); + goto err_end; + } + if (status & FDC1772STAT_CRC) { + printk("fd%d: CRC error (side %d, track %d, sector %d)\n", + SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR)); + goto err_end; + } + if (status & FDC1772STAT_LOST) { + printk("fd%d: lost data (side %d, track %d, sector %d)\n", + SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR)); + goto err_end; + } + Probing = 0; + + if (ReqCmd == READ) { +#ifdef TRACKBUFFER + if (!read_track) + { + /*cache_clear (PhysDMABuffer, 512);*/ + copy_buffer (DMABuffer, ReqData); + } + else + { + /*cache_clear (PhysTrackBuffer, MAX_SECTORS * 512);*/ + BufferDrive = SelectedDrive; + BufferSide = ReqSide; + BufferTrack = ReqTrack; + copy_buffer (SECTOR_BUFFER (ReqSector), ReqData); + } +#else + /*cache_clear( PhysDMABuffer, 512 ); */ + copy_buffer(DMABuffer, ReqData); +#endif + } + if (++ReqCnt < CURRENT->current_nr_sectors) { + /* read next sector */ + setup_req_params(SelectedDrive); + do_fd_action(SelectedDrive); + } else { + /* all sectors finished */ + CURRENT->nr_sectors -= CURRENT->current_nr_sectors; + CURRENT->sector += CURRENT->current_nr_sectors; + end_request(1); + redo_fd_request(); + } + return; + + err_end: +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + + fd_error(); +} + + +static void fd_times_out(unsigned long dummy) +{ + SET_IRQ_HANDLER(NULL); + /* If the timeout occured while the readtrack_check timer was + * active, we need to cancel it, else bad things will happen */ + del_timer( &readtrack_timer ); + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); + udelay(25); + + printk("floppy timeout\n"); + STOP_TIMEOUT(); /* hmm - should we do this ? */ + fd_error(); +} + + +/* The (noop) seek operation here is needed to make the WP bit in the + * FDC1772 status register accessible for check_change. If the last disk + * operation would have been a RDSEC, this bit would always read as 0 + * no matter what :-( To save time, the seek goes to the track we're + * already on. + */ + +static void finish_fdc(void) +{ + /* DAG - just try without this dummy seek! */ + finish_fdc_done(0); + return; + + if (!NeedSeek) { + finish_fdc_done(0); + } else { + DPRINT(("finish_fdc: dummy seek started\n")); + FDC1772_WRITE(FDC1772REG_DATA, unit[SelectedDrive].track); + SET_IRQ_HANDLER(finish_fdc_done); + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK); + MotorOn = 1; + START_TIMEOUT(); + /* we must wait for the IRQ here, because the ST-DMA is + * released immediatly afterwards and the interrupt may be + * delivered to the wrong driver. + */ + } +} + + +static void finish_fdc_done(int dummy) +{ + unsigned long flags; + + DPRINT(("finish_fdc_done entered\n")); + STOP_TIMEOUT(); + NeedSeek = 0; + + if ((timer_active & (1 << FLOPPY_TIMER)) && + timer_table[FLOPPY_TIMER].expires < jiffies + 5) + /* If the check for a disk change is done too early after this + * last seek command, the WP bit still reads wrong :-(( + */ + timer_table[FLOPPY_TIMER].expires = jiffies + 5; + else { + /* START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */ + }; + del_timer(&motor_off_timer); + START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY); + + save_flags(flags); + cli(); + /* stdma_release(); - not sure if I should do something DAG */ + fdc_busy = 0; + wake_up(&fdc_wait); + restore_flags(flags); + + DPRINT(("finish_fdc() finished\n")); +} + + +/* Prevent "aliased" accesses. */ +static fd_ref[4] = +{0, 0, 0, 0}; +static fd_device[4] = +{0, 0, 0, 0}; + +/* + * Current device number. Taken either from the block header or from the + * format request descriptor. + */ +#define CURRENT_DEVICE (CURRENT->rq_dev) + +/* Current error count. */ +#define CURRENT_ERRORS (CURRENT->errors) + + +/* dummy for blk.h */ +static void floppy_off(unsigned int nr) +{ +} + + +/* On the old arcs write protect depends on the particular model + of machine. On the A310, R140, and A440 there is a disc changed + detect, however on the A4x0/1 range there is not. There + is nothing to tell you which machine your on. + At the moment I'm just marking changed always. I've + left the Atari's 'change on write protect change' code in this + part (but nothing sets it). + RiscOS apparently checks the disc serial number etc. to detect changes + - but if it sees a disc change line go high (?) it flips to using + it. Well maybe I'll add that in the future (!?) +*/ +static int check_floppy_change(dev_t dev) +{ + unsigned int drive = (dev & 0x03); + + if (MAJOR(dev) != MAJOR_NR) { + printk("floppy_changed: not a floppy\n"); + return 0; + } + if (test_bit(drive, &fake_change)) { + /* simulated change (e.g. after formatting) */ + return 1; + } + if (test_bit(drive, &changed_floppies)) { + /* surely changed (the WP signal changed at least once) */ + return 1; + } + if (unit[drive].wpstat) { + /* WP is on -> could be changed: to be sure, buffers should be + * invalidated... + */ + return 1; + } + return 1; /* DAG - was 0 */ +} + +static int floppy_revalidate(dev_t dev) +{ + int drive = dev & 3; + + if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) + || unit[drive].disktype == 0) { +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + clear_bit(drive, &fake_change); + clear_bit(drive, &changed_floppies); + unit[drive].disktype = 0; + } + return 0; +} + +static __inline__ void copy_buffer(void *from, void *to) +{ + ulong *p1 = (ulong *) from, *p2 = (ulong *) to; + int cnt; + + for (cnt = 512 / 4; cnt; cnt--) + *p2++ = *p1++; +} + + +/* This sets up the global variables describing the current request. */ + +static void setup_req_params(int drive) +{ + int block = ReqBlock + ReqCnt; + + ReqTrack = block / unit[drive].disktype->spt; + ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1; + ReqSide = ReqTrack & 1; + ReqTrack >>= 1; + ReqData = ReqBuffer + 512 * ReqCnt; + +#ifdef TRACKBUFFER + read_track = (ReqCmd == READ && CURRENT_ERRORS == 0); +#endif + + DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide, + ReqTrack, ReqSector, (unsigned long) ReqData)); +} + + +static void redo_fd_request(void) +{ + int device, drive, type; + struct archy_floppy_struct *floppy; + + DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->rq_dev=%04x CURRENT->sector=%ld\n", + (unsigned long) CURRENT, CURRENT ? CURRENT->rq_dev : 0, + CURRENT ? CURRENT->sector : 0)); + + if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) + goto the_end; + + repeat: + + if (!CURRENT) + goto the_end; + + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) + panic(DEVICE_NAME ": request list destroyed"); + + if (CURRENT->bh) { + if (!buffer_locked(CURRENT->bh)) + panic(DEVICE_NAME ": block not locked"); + } + device = MINOR(CURRENT_DEVICE); + drive = device & 3; + type = device >> 2; + floppy = &unit[drive]; + + if (!floppy->connected) { + /* drive not connected */ + printk("Unknown Device: fd%d\n", drive); + end_request(0); + goto repeat; + } + if (type == 0) { + if (!floppy->disktype) { + Probing = 1; + floppy->disktype = disk_type + NUM_DISK_TYPES - 1; + floppy_sizes[drive] = floppy->disktype->blocks >> 1; + floppy->autoprobe = 1; + } + } else { + /* user supplied disk type */ + --type; + if (type >= NUM_DISK_TYPES) { + printk("fd%d: invalid disk format", drive); + end_request(0); + goto repeat; + } + floppy->disktype = &disk_type[type]; + floppy_sizes[drive] = disk_type[type].blocks >> 1; + floppy->autoprobe = 0; + } + + if (CURRENT->sector + 1 > floppy->disktype->blocks) { + end_request(0); + goto repeat; + } + /* stop deselect timer */ + del_timer(&motor_off_timer); + + ReqCnt = 0; + ReqCmd = CURRENT->cmd; + ReqBlock = CURRENT->sector; + ReqBuffer = CURRENT->buffer; + setup_req_params(drive); + do_fd_action(drive); + + return; + + the_end: + finish_fdc(); +} + +static void fd1772_checkint(void) +{ + extern int fdc1772_bytestogo; + + /*printk("fd1772_checkint %d\n",fdc1772_fdc_int_done);*/ + if (fdc1772_fdc_int_done) + floppy_irqconsequencehandler(); + if ((MultReadInProgress) && (fdc1772_bytestogo==0)) fd_readtrack_check(0); + if (fdc_busy) { + queue_task(&fd1772_tq,&tq_immediate); + mark_bh(IMMEDIATE_BH); + }; +}; + +void do_fd_request(void) +{ + unsigned long flags; + + DPRINT(("do_fd_request for pid %d\n", current->pid)); + if (fdc_busy) return; + save_flags(flags); + cli(); + while (fdc_busy) + sleep_on(&fdc_wait); + fdc_busy = 1; + ENABLE_IRQ(); + restore_flags(flags); + + fdc1772_fdc_int_done = 0; + + redo_fd_request(); + + queue_task(&fd1772_tq,&tq_immediate); + mark_bh(IMMEDIATE_BH); +} + + +static int invalidate_drive(int rdev) +{ + /* invalidate the buffer track to force a reread */ +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + + set_bit(rdev & 3, &fake_change); + check_disk_change(rdev); + return 0; +} + +static int fd_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long param) +{ +#define IOCTL_MODE_BIT 8 +#define OPEN_WRITE_BIT 16 +#define IOCTL_ALLOWED (filp && (filp->f_mode & IOCTL_MODE_BIT)) + + int drive, device; + + device = inode->i_rdev; + switch (cmd) { + RO_IOCTLS(inode->i_rdev, param); + } + drive = MINOR(device); + if (!IOCTL_ALLOWED) + return -EPERM; + switch (cmd) { + case FDFMTBEG: + return 0; + /* case FDC1772LRPRM: ??? DAG what does this do?? + unit[drive].disktype = NULL; + floppy_sizes[drive] = MAX_DISK_SIZE; + return invalidate_drive (device); */ + case FDFMTEND: + case FDFLUSH: + return invalidate_drive(drive); + } + if (!suser()) + return -EPERM; + if (drive < 0 || drive > 3) + return -EINVAL; + switch (cmd) { + default: + return -EINVAL; + } + return 0; +} + + +/* Initialize the 'unit' variable for drive 'drive' */ + +static void fd_probe(int drive) +{ + unit[drive].connected = 0; + unit[drive].disktype = NULL; + + if (!fd_test_drive_present(drive)) + return; + + unit[drive].connected = 1; + unit[drive].track = -1; /* If we put the auto detect back in this can go to 0 */ + unit[drive].steprate = FDC1772STEP_6; + MotorOn = 1; /* from probe restore operation! */ +} + + +/* This function tests the physical presence of a floppy drive (not + * whether a disk is inserted). This is done by issuing a restore + * command, waiting max. 2 seconds (that should be enough to move the + * head across the whole disk) and looking at the state of the "TR00" + * signal. This should now be raised if there is a drive connected + * (and there is no hardware failure :-) Otherwise, the drive is + * declared absent. + */ + +static int fd_test_drive_present(int drive) +{ + unsigned long timeout; + unsigned char status; + int ok; + + printk("fd_test_drive_present %d\n", drive); + if (drive > 1) + return (0); + return (1); /* Simple hack for the moment - the autodetect doesn't seem to work on arc */ + fd_select_drive(drive); + + /* disable interrupt temporarily */ + DISABLE_IRQ(); + FDC1772_WRITE(FDC1772REG_TRACK, 0x00); /* was ff00 why? */ + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6); + + /*printk("fd_test_drive_present: Going into timeout loop\n"); */ + for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; jiffies < timeout;) { + /* What does this piece of atariism do? - query for an interrupt? */ + /* if (!(mfp.par_dt_reg & 0x20)) + break; */ + /* Well this is my nearest guess - quit when we get an FDC interrupt */ + if (IOC_FIQSTAT & 2) + break; + } + + /*printk("fd_test_drive_present: Coming out of timeout loop\n"); */ + status = FDC1772_READ(FDC1772REG_STATUS); + ok = (status & FDC1772STAT_TR00) != 0; + + /*printk("fd_test_drive_present: ok=%d\n",ok); */ + /* force interrupt to abort restore operation (FDC1772 would try + * about 50 seconds!) */ + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); + udelay(500); + status = FDC1772_READ(FDC1772REG_STATUS); + udelay(20); + /*printk("fd_test_drive_present: just before OK code %d\n",ok); */ + + if (ok) { + /* dummy seek command to make WP bit accessible */ + FDC1772_WRITE(FDC1772REG_DATA, 0); + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK); + printk("fd_test_drive_present: just before wait for int\n"); + /* DAG: Guess means wait for interrupt */ + while (!(IOC_FIQSTAT & 2)); + printk("fd_test_drive_present: just after wait for int\n"); + status = FDC1772_READ(FDC1772REG_STATUS); + } + printk("fd_test_drive_present: just before ENABLE_IRQ\n"); + ENABLE_IRQ(); + printk("fd_test_drive_present: about to return\n"); + return (ok); +} + + +/* Look how many and which kind of drives are connected. If there are + * floppies, additionally start the disk-change and motor-off timers. + */ + +static void config_types(void) +{ + int drive, cnt = 0; + + printk("Probing floppy drive(s):\n"); + for (drive = 0; drive < FD_MAX_UNITS; drive++) { + fd_probe(drive); + if (unit[drive].connected) { + printk("fd%d\n", drive); + ++cnt; + } + } + + if (FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_BUSY) { + /* If FDC1772 is still busy from probing, give it another FORCI + * command to abort the operation. If this isn't done, the FDC1772 + * will interrupt later and its IRQ line stays low, because + * the status register isn't read. And this will block any + * interrupts on this IRQ line :-( + */ + FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); + udelay(500); + FDC1772_READ(FDC1772REG_STATUS); + udelay(20); + } + if (cnt > 0) { + START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY); + if (cnt == 1) + fd_select_drive(0); + /*START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */ + } +} + +/* + * floppy_open check for aliasing (/dev/fd0 can be the same as + * /dev/PS0 etc), and disallows simultaneous access to the same + * drive with different device numbers. + */ + +static int floppy_open(struct inode *inode, struct file *filp) +{ + int drive; + int old_dev; + + if (!filp) { + DPRINT(("Weird, open called with filp=0\n")); + return -EIO; + } + drive = MINOR(inode->i_rdev) & 3; + if ((MINOR(inode->i_rdev) >> 2) > NUM_DISK_TYPES) + return -ENXIO; + + old_dev = fd_device[drive]; + + if (fd_ref[drive]) + if (old_dev != inode->i_rdev) + return -EBUSY; + + if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) + return -EBUSY; + + if (filp->f_flags & O_EXCL) + fd_ref[drive] = -1; + else + fd_ref[drive]++; + + fd_device[drive] = inode->i_rdev; + + if (old_dev && old_dev != inode->i_rdev) + invalidate_buffers(old_dev); + + /* Allow ioctls if we have write-permissions even if read-only open */ + if (filp->f_mode & 2 || permission(inode, 2) == 0) + filp->f_mode |= IOCTL_MODE_BIT; + if (filp->f_mode & 2) + filp->f_mode |= OPEN_WRITE_BIT; + + if (filp->f_flags & O_NDELAY) + return 0; + + if (filp->f_mode & 3) { + check_disk_change(inode->i_rdev); + if (filp->f_mode & 2) { + if (unit[drive].wpstat) { + floppy_release(inode, filp); + return -EROFS; + } + } + } + return 0; +} + + +static void floppy_release(struct inode *inode, struct file *filp) +{ + int drive; + + drive = inode->i_rdev & 3; + + if (!filp || (filp->f_mode & (2 | OPEN_WRITE_BIT))) + /* if the file is mounted OR (writable now AND writable at open + time) Linus: Does this cover all cases? */ + block_fsync(inode, filp); + + if (fd_ref[drive] < 0) + fd_ref[drive] = 0; + else if (!fd_ref[drive]--) { + printk("floppy_release with fd_ref == 0"); + fd_ref[drive] = 0; + } +} + +static struct file_operations floppy_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + fd_ioctl, /* ioctl */ + NULL, /* mmap */ + floppy_open, /* open */ + floppy_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + check_floppy_change, /* media_change */ + floppy_revalidate, /* revalidate */ +}; + + +int floppy_init(void) +{ + int i; + + if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { + printk("Unable to get major %d for floppy\n", MAJOR_NR); + return 1; + } + + if (request_dma(FLOPPY_DMA, "fd1772")) { + printk("Unable to grab DMA%d for the floppy (1772) driver\n", FLOPPY_DMA); + return 1; + }; + + if (request_dma(FIQ_FD1772, "fd1772 end")) { + printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772); + free_dma(FLOPPY_DMA); + return 1; + }; + enable_dma(FIQ_FD1772); /* This inserts a call to our command end routine */ + + /* initialize variables */ + SelectedDrive = -1; +#ifdef TRACKBUFFER + BufferDrive = -1; +#endif + + /* initialize check_change timer */ + timer_table[FLOPPY_TIMER].fn = check_change; + timer_active &= ~(1 << FLOPPY_TIMER); + + +#ifdef TRACKBUFFER + DMABuffer = (char *)kmalloc((MAX_SECTORS+1)*512,GFP_KERNEL); /* Atari uses 512 - I want to eventually cope with 1K sectors */ + TrackBuffer = DMABuffer + 512; +#else + /* Allocate memory for the DMAbuffer - on the Atari this takes it + out of some special memory... */ + DMABuffer = (char *) kmalloc(2048); /* Copes with pretty large sectors */ +#endif +#ifdef TRACKBUFFER + BufferDrive = BufferSide = BufferTrack = -1; +#endif + + for (i = 0; i < FD_MAX_UNITS; i++) { + unit[i].track = -1; + } + + for (i = 0; i < 256; i++) + if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_TYPES) + floppy_sizes[i] = disk_type[(i >> 2) - 1].blocks >> 1; + else + floppy_sizes[i] = MAX_DISK_SIZE; + + blk_size[MAJOR_NR] = floppy_sizes; + blksize_size[MAJOR_NR] = floppy_blocksizes; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + + config_types(); + + return 0; +} + +/* Just a dummy at the moment */ +void floppy_setup(char *str, int *ints) +{ +} + +void floppy_eject(void) { +} diff -ur --new-file old/linux/drivers/acorn/block/ide-ics.c new/linux/drivers/acorn/block/ide-ics.c --- old/linux/drivers/acorn/block/ide-ics.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/block/ide-ics.c Mon Feb 16 23:26:56 1998 @@ -0,0 +1,271 @@ +/* + * linux/arch/arm/drivers/block/ide-ics.c + * + * Copyright (c) 1996,1997 Russell King. + * + * Changelog: + * 08-06-1996 RMK Created + * 12-09-1997 RMK Added interrupt enable/disable + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../../block/ide.h" + +/* + * Maximum number of interfaces per card + */ +#define MAX_IFS 2 + +#define ICS_IDENT_OFFSET 0x8a0 + +#define ICS_ARCIN_V5_INTROFFSET 0x001 +#define ICS_ARCIN_V5_IDEOFFSET 0xa00 +#define ICS_ARCIN_V5_IDEALTOFFSET 0xae0 +#define ICS_ARCIN_V5_IDESTEPPING 4 + +#define ICS_ARCIN_V6_IDEOFFSET_1 0x800 +#define ICS_ARCIN_V6_INTROFFSET_1 0x880 +#define ICS_ARCIN_V6_IDEALTOFFSET_1 0x8e0 +#define ICS_ARCIN_V6_IDEOFFSET_2 0xc00 +#define ICS_ARCIN_V6_INTROFFSET_2 0xc80 +#define ICS_ARCIN_V6_IDEALTOFFSET_2 0xce0 +#define ICS_ARCIN_V6_IDESTEPPING 4 + +static const card_ids icside_cids[] = { + { MANU_ICS, PROD_ICS_IDE }, + { 0xffff, 0xffff } +}; + +typedef enum { + ics_if_unknown, + ics_if_arcin_v5, + ics_if_arcin_v6 +} iftype_t; + +static struct expansion_card *ec[MAX_ECARDS]; +static int result[MAX_ECARDS][MAX_IFS]; + + +/* ---------------- Version 5 PCB Support Functions --------------------- */ +/* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + unsigned int memc_port = (unsigned int)ec->irq_data; + outb (0, memc_port + ICS_ARCIN_V5_INTROFFSET); +} + +/* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr) +{ + unsigned int memc_port = (unsigned int)ec->irq_data; + inb (memc_port + ICS_ARCIN_V5_INTROFFSET); +} + +static const expansioncard_ops_t icside_ops_arcin_v5 = { + icside_irqenable_arcin_v5, + icside_irqdisable_arcin_v5, + NULL, + NULL +}; + + +/* ---------------- Version 6 PCB Support Functions --------------------- */ +/* Prototype: icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : enable interrupts from card + */ +static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + unsigned int ide_base_port = (unsigned int)ec->irq_data; + outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); + outb (0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); +} + +/* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) + * Purpose : disable interrupts from card + */ +static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) +{ + unsigned int ide_base_port = (unsigned int)ec->irq_data; + inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_1); + inb (ide_base_port + ICS_ARCIN_V6_INTROFFSET_2); +} + +static const expansioncard_ops_t icside_ops_arcin_v6 = { + icside_irqenable_arcin_v6, + icside_irqdisable_arcin_v6, + NULL, + NULL +}; + + + +/* Prototype: icside_identifyif (struct expansion_card *ec) + * Purpose : identify IDE interface type + * Notes : checks the description string + */ +static iftype_t icside_identifyif (struct expansion_card *ec) +{ + unsigned int addr; + iftype_t iftype; + int id = 0; + + iftype = ics_if_unknown; + + addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET; + + id = inb (addr) & 1; + id |= (inb (addr + 1) & 1) << 1; + id |= (inb (addr + 2) & 1) << 2; + id |= (inb (addr + 3) & 1) << 3; + + switch (id) { + case 0: /* A3IN */ + printk ("icside: A3IN unsupported\n"); + break; + + case 1: /* A3USER */ + printk ("icside: A3USER unsupported\n"); + break; + + case 3: /* ARCIN V6 */ + printk ("icside: detected ARCIN V6 in slot %d\n", ec->slot_no); + iftype = ics_if_arcin_v6; + break; + + case 15:/* ARCIN V5 (no id) */ + printk ("icside: detected ARCIN V5 in slot %d\n", ec->slot_no); + iftype = ics_if_arcin_v5; + break; + + default:/* we don't know - complain very loudly */ + printk ("icside: ***********************************\n"); + printk ("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id); + printk ("icside: ***********************************\n"); + printk ("icside: please report this to: linux@arm.uk.linux.org\n"); + printk ("icside: defaulting to ARCIN V5\n"); + iftype = ics_if_arcin_v5; + break; + } + + return iftype; +} + +/* Prototype: icside_register (struct expansion_card *ec) + * Purpose : register an ICS IDE card with the IDE driver + * Notes : we make sure that interrupts are disabled from the card + */ +static inline void icside_register (struct expansion_card *ec, int index) +{ + unsigned long port; + + result[index][0] = -1; + result[index][1] = -1; + + switch (icside_identifyif (ec)) { + case ics_if_unknown: + default: + printk ("** Warning: ICS IDE Interface unrecognised! **\n"); + break; + + case ics_if_arcin_v5: + port = ecard_address (ec, ECARD_MEMC, 0); + ec->irq_data = (void *)port; + ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v5; + + /* + * Be on the safe side - disable interrupts + */ + inb (port + ICS_ARCIN_V5_INTROFFSET); + result[index][0] = + ide_register_port (port + ICS_ARCIN_V5_IDEOFFSET, + port + ICS_ARCIN_V5_IDEALTOFFSET, + ICS_ARCIN_V5_IDESTEPPING, + ec->irq); + break; + + case ics_if_arcin_v6: + port = ecard_address (ec, ECARD_IOC, ECARD_FAST); + ec->irq_data = (void *)port; + ec->ops = (expansioncard_ops_t *)&icside_ops_arcin_v6; + + /* + * Be on the safe side - disable interrupts + */ + inb (port + ICS_ARCIN_V6_INTROFFSET_1); + inb (port + ICS_ARCIN_V6_INTROFFSET_2); + result[index][0] = + ide_register_port (port + ICS_ARCIN_V6_IDEOFFSET_1, + port + ICS_ARCIN_V6_IDEALTOFFSET_1, + ICS_ARCIN_V6_IDESTEPPING, + ec->irq); + result[index][1] = + ide_register_port (port + ICS_ARCIN_V6_IDEOFFSET_2, + port + ICS_ARCIN_V6_IDEALTOFFSET_2, + ICS_ARCIN_V6_IDESTEPPING, + ec->irq); + break; + } +} + +int icside_init (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + ec[i] = NULL; + + ecard_startfind (); + + for (i = 0; ; i++) { + if ((ec[i] = ecard_find (0, icside_cids)) == NULL) + break; + + ecard_claim (ec[i]); + icside_register (ec[i], i); + } + + for (i = 0; i < MAX_ECARDS; i++) + if (ec[i] && result[i][0] < 0 && result[i][1] < 0) { + ecard_release (ec[i]); + ec[i] = NULL; + } + return 0; +} + +#ifdef MODULE +int init_module (void) +{ + return icside_init(); +} + +void cleanup_module (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + if (ec[i]) { + if (result[i][0] >= 0) + ide_unregister (result[i][0]); + + if (result[i][1] >= 0) + ide_unregister (result[i][1]); + + ecard_release (ec[i]); + ec[i] = NULL; + } +} +#endif + diff -ur --new-file old/linux/drivers/acorn/block/ide-rapide.c new/linux/drivers/acorn/block/ide-rapide.c --- old/linux/drivers/acorn/block/ide-rapide.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/block/ide-rapide.c Mon Feb 16 23:27:05 1998 @@ -0,0 +1,78 @@ +/* + * linux/arch/arm/drivers/block/ide-ics.c + * + * Copyright (c) 1996 Russell King. + * + * Changelog: + * 08-06-1996 RMK Created + */ + +#include +#include +#include +#include +#include + +#include "../../block/ide.h" + +static const card_ids rapide_cids[] = { + { 0xffff, 0xffff } +}; + +static struct expansion_card *ec[MAX_ECARDS]; +static int result[MAX_ECARDS]; + +static inline int rapide_register (struct expansion_card *ec) +{ + unsigned long port = ecard_address (ec, ECARD_MEMC, 0); + + return ide_register_port (port, port + 0x206, 4, ec->irq); +} + +int rapide_init (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + ec[i] = NULL; + + ecard_startfind (); + + for (i = 0; ; i++) { + if ((ec[i] = ecard_find (0, rapide_cids)) == NULL) + break; + + ecard_claim (ec[i]); + result[i] = rapide_register (ec[i]); + } + for (i = 0; i < MAX_ECARDS; i++) + if (ec[i] && result[i] < 0) { + ecard_release (ec[i]); + ec[i] = NULL; + } + return 0; +} + +#ifdef MODULE + +int init_module (void) +{ + return rapide_init(); +} + +void cleanup_module (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + if (ec[i]) { + unsigned long port; + port = ecard_address (ec[i], ECARD_MEMC, 0); + + ide_unregister_port (port, ec[i]->irq, 16); + ecard_release (ec[i]); + ec[i] = NULL; + } +} +#endif + diff -ur --new-file old/linux/drivers/acorn/block/mfmhd.c new/linux/drivers/acorn/block/mfmhd.c --- old/linux/drivers/acorn/block/mfmhd.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/block/mfmhd.c Mon Jan 26 23:03:39 1998 @@ -0,0 +1,1549 @@ +/* + * linux/arch/arm/drivers/block/mfmhd.c + * + * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk) + * + * MFM hard drive code [experimental] + */ + +/* + * Change list: + * + * 3/2/96:DAG: Started a change list :-) + * Set the hardsect_size pointers up since we are running 256 byte + * sectors + * Added DMA code, put it into the rw_intr + * Moved RCAL out of generic interrupt code - don't want to do it + * while DMA'ing - its now in individual handlers. + * Took interrupt handlers off task queue lists and called + * directly - not sure of implications. + * + * 18/2/96:DAG: Well its reading OK I think, well enough for image file code + * to find the image file; but now I've discovered that I actually + * have to put some code in for image files. + * + * Added stuff for image files; seems to work, but I've not + * got a multisegment image file (I don't think!). + * Put in a hack (yep a real hack) for multiple cylinder reads. + * Not convinced its working. + * + * 5/4/96:DAG: Added asm/hardware.h and use IOC_ macros + * Rewrote dma code in mfm.S (again!) - now takes a word at a time + * from main RAM for speed; still doesn't feel speedy! + * + * 20/4/96:DAG: After rewriting mfm.S a heck of a lot of times and speeding + * things up, I've finally figured out why its so damn slow. + * Linux is only reading a block at a time, and so you never + * get more than 1K per disc revoloution ~=60K/second. + * + * 27/4/96:DAG: On Russell's advice I change ll_rw_blk.c to ask it to + * join adjacent blocks together. Everything falls flat on its + * face. + * Four hours of debugging later; I hadn't realised that + * ll_rw_blk would be so generous as to join blocks whose + * results aren't going into consecutive buffers. + * + * OK; severe rehacking of mfm_rw_interrupt; now end_request's + * as soon as its DMA'd each request. Odd thing is that + * we are sometimes getting interrupts where we are not transferring + * any data; why? Is that what happens when you miss? I doubt + * it; are we too fast? No - its just at command ends. Got 240K/s + * better than before, but RiscOS hits 480K/s + * + * 25/6/96:RMK: Fixed init code to allow the MFM podule to work. Increased the + * number of errors for my Miniscribe drive (8425). + * + * 30/6/96:DAG: Russell suggested that a check drive 0 might turn the LEDs off + * - so in request_done just before it clears Busy it sends a + * check drive 0 - and the LEDs go off!!!! + * + * Added test for mainboard controller. - Removes need for separate + * define. + * + * 13/7/96:DAG: Changed hardware sectore size to 512 in attempt to make + * IM drivers work. + * 21/7/96:DAG: Took out old image file stuff (accessing it now produces an IO + * error.) + * + * 17/8/96:DAG: Ran through indent -kr -i8; evil - all my nice 2 character indents + * gone :-( Hand modified afterwards. + * Took out last remains of the older image map system. + * + * 22/9/96:DAG: Changed mfm.S so it will carry on DMA'ing til; BSY is dropped + * Changed mfm_rw_intr so that it doesn't follow the error + * code until BSY is dropped. Nope - still broke. Problem + * may revolve around when it reads the results for the error + * number? + * + *16/11/96:DAG: Modified for 2.0.18; request_irq changed + * + *17/12/96:RMK: Various cleanups, reorganisation, and the changes for new IO system. + * Improved probe for onboard MFM chip - it was hanging on my A5k. + * Added autodetect CHS code such that we don't rely on the presence + * of an ADFS boot block. Added ioport resource manager calls so + * that we don't clash with already-running hardware (eg. RiscPC Ether + * card slots if someone tries this)! + * + * 17/1/97:RMK: Upgraded to 2.1 kernels. + */ + +/* + * Possible enhancements: + * Multi-thread the code so that it is possible that while one drive + * is seeking, the other one can be reading data/seeking as well. + * This would be a performance boost with dual drive systems. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MFM_DISK_MAJOR 13 +#undef XT_DISK_MAJOR +#define XT_DISK_MAJOR -1 +#define MAJOR_NR MFM_DISK_MAJOR +#include "blk.h" + +/* + * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc + */ +#ifndef HDIO_GETGEO +#define HDIO_GETGEO 0x301 +struct hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + unsigned long start; +}; +#endif + + +/* + * Configuration section + * + * This is the maximum number of drives that we accept + */ +#define MFM_MAXDRIVES 2 +/* + * Linux I/O address of onboard MFM controller or 0 to disable this + */ +#define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000) +/* + * Uncomment this to enable debugging in the MFM driver... + */ +#ifndef DEBUG +/*#define DEBUG */ +#endif +/* + * List of card types that we recognise + */ +static const card_ids mfm_cids[] = { + { MANU_ACORN, PROD_ACORN_MFM }, + { 0xffff, 0xffff } +}; +/* + * End of configuration + */ + + +/* + * This structure contains all information to do with a particular physical + * device. + */ +struct mfm_info { + unsigned char sectors; + unsigned char heads; + unsigned short cylinders; + unsigned short lowcurrent; + unsigned short precomp; +#define NO_TRACK -1 +#define NEED_1_RECAL -2 +#define NEED_2_RECAL -3 + int cylinder; + unsigned int access_count; + unsigned int busy; + struct { + char recal; + char report; + char abort; + } errors; +} mfm_info[MFM_MAXDRIVES]; + +#define MFM_DRV_INFO mfm_info[raw_cmd.dev] + +static struct hd_struct mfm[MFM_MAXDRIVES << 6]; +static int mfm_sizes[MFM_MAXDRIVES << 6]; +static int mfm_blocksizes[MFM_MAXDRIVES << 6]; +static int mfm_sectsizes[MFM_MAXDRIVES << 6]; +static struct wait_queue *mfm_wait_open = NULL; + +/* Stuff from the assembly routines */ +extern unsigned int hdc63463_baseaddress; /* Controller base address */ +extern unsigned int hdc63463_irqpolladdress; /* Address to read to test for int */ +extern unsigned int hdc63463_irqpollmask; /* Mask for irq register */ +extern unsigned int hdc63463_dataptr; /* Pointer to kernel data space to DMA */ +extern int hdc63463_dataleft; /* Number of bytes left to transfer */ + + + + +static int lastspecifieddrive; +static unsigned Busy; + +static unsigned int PartFragRead; /* The number of sectors which have been read + during a partial read split over two + cylinders. If 0 it means a partial + read did not occur. */ + +static unsigned int PartFragRead_RestartBlock; /* Where to restart on a split access */ +static unsigned int PartFragRead_SectorsLeft; /* Where to restart on a split access */ + +static int Sectors256LeftInCurrent; /* i.e. 256 byte sectors left in current */ +static int SectorsLeftInRequest; /* i.e. blocks left in the thing mfm_request was called for */ +static int Copy_Sector; /* The 256 byte sector we are currently at - fragments need to know + where to take over */ +static char *Copy_buffer; + + +static void mfm_seek(void); +static void mfm_rerequest(void); +static void mfm_request(void); +static int mfm_reread_partitions(kdev_t dev); +static void mfm_specify (void); +static void issue_request(int dev, unsigned int block, unsigned int nsect, + struct request *req); + +#define mfm_init xd_init +#define mfm_setup xd_setup + +static unsigned int mfm_addr; /* Controller address */ +static unsigned int mfm_IRQPollLoc; /* Address to read for IRQ information */ +static unsigned int mfm_irqenable; /* Podule IRQ enable location */ +static unsigned char mfm_irq; /* Interrupt number */ +static int mfm_drives = 0; /* drives available */ +static int mfm_status = 0; /* interrupt status */ +static int *errors; + +static struct rawcmd { + unsigned int dev; + unsigned int cylinder; + unsigned int head; + unsigned int sector; + unsigned int cmdtype; + unsigned int cmdcode; + unsigned char cmddata[16]; + unsigned int cmdlen; +} raw_cmd; + +static unsigned char result[16]; + +static struct cont { + void (*interrupt) (void); /* interrupt handler */ + void (*error) (void); /* error handler */ + void (*redo) (void); /* redo handler */ + void (*done) (int st); /* done handler */ +} *cont = NULL; + +static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0}; + +int number_mfm_drives = 1; + +/* ------------------------------------------------------------------------------------------ */ +/* + * From the HD63463 data sheet from Hitachi Ltd. + */ + +#define MFM_COMMAND (mfm_addr + 0) +#define MFM_DATAOUT (mfm_addr + 1) +#define MFM_STATUS (mfm_addr + 8) +#define MFM_DATAIN (mfm_addr + 9) + +#define CMD_ABT 0xF0 /* Abort */ +#define CMD_SPC 0xE8 /* Specify */ +#define CMD_TST 0xE0 /* Test */ +#define CMD_RCLB 0xC8 /* Recalibrate */ +#define CMD_SEK 0xC0 /* Seek */ +#define CMD_WFS 0xAB /* Write Format Skew */ +#define CMD_WFM 0xA3 /* Write Format */ +#define CMD_MTB 0x90 /* Memory to buffer */ +#define CMD_CMPD 0x88 /* Compare data */ +#define CMD_WD 0x87 /* Write data */ +#define CMD_RED 0x70 /* Read erroneous data */ +#define CMD_RIS 0x68 /* Read ID skew */ +#define CMD_FID 0x61 /* Find ID */ +#define CMD_RID 0x60 /* Read ID */ +#define CMD_BTM 0x50 /* Buffer to memory */ +#define CMD_CKD 0x48 /* Check data */ +#define CMD_RD 0x40 /* Read data */ +#define CMD_OPBW 0x38 /* Open buffer write */ +#define CMD_OPBR 0x30 /* Open buffer read */ +#define CMD_CKV 0x28 /* Check drive */ +#define CMD_CKE 0x20 /* Check ECC */ +#define CMD_POD 0x18 /* Polling disable */ +#define CMD_POL 0x10 /* Polling enable */ +#define CMD_RCAL 0x08 /* Recall */ + +#define STAT_BSY 0x8000 /* Busy */ +#define STAT_CPR 0x4000 /* Command Parameter Rejection */ +#define STAT_CED 0x2000 /* Command end */ +#define STAT_SED 0x1000 /* Seek end */ +#define STAT_DER 0x0800 /* Drive error */ +#define STAT_ABN 0x0400 /* Abnormal end */ +#define STAT_POL 0x0200 /* Polling */ + +/* ------------------------------------------------------------------------------------------ */ +#ifdef DEBUG +static void console_printf(const char *fmt,...) +{ + static char buffer[2048]; /* Arbitary! */ + extern void console_print(const char *); + unsigned long flags; + va_list ap; + + save_flags_cli(flags); + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + console_print(buffer); + va_end(fmt); + + restore_flags(flags); +}; /* console_printf */ + +#define DBG(x...) console_printf(x) +#else +#define DBG(x...) +#endif + +static void print_status(void) +{ + char *error; + static char *errors[] = { + "no error", + "command aborted", + "invalid command", + "parameter error", + "not initialised", + "rejected TEST", + "no useld", + "write fault", + "not ready", + "no scp", + "in seek", + "invalid NCA", + "invalid step rate", + "seek error", + "over run", + "invalid PHA", + "data field EEC error", + "data field CRC error", + "error corrected", + "data field fatal error", + "no data am", + "not hit", + "ID field CRC error", + "time over", + "no ID am", + "not writable" + }; + if (result[1] < 0x65) + error = errors[result[1] >> 2]; + else + error = "unknown"; + printk("("); + if (mfm_status & STAT_BSY) printk("BSY "); + if (mfm_status & STAT_CPR) printk("CPR "); + if (mfm_status & STAT_CED) printk("CED "); + if (mfm_status & STAT_SED) printk("SED "); + if (mfm_status & STAT_DER) printk("DER "); + if (mfm_status & STAT_ABN) printk("ABN "); + if (mfm_status & STAT_POL) printk("POL "); + printk(") SSB = %X (%s)\n", result[1], error); + +} + +/* ------------------------------------------------------------------------------------- */ + +static void issue_command(int command, unsigned char *cmdb, int len) +{ + int status; +#ifdef DEBUG + int i; + console_printf("issue_command: %02X: ", command); + for (i = 0; i < len; i++) + console_printf("%02X ", cmdb[i]); + console_printf("\n"); +#endif + + do { + status = inw(MFM_STATUS); + } while (status & (STAT_BSY | STAT_POL)); + DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8); + + if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) { + outw(CMD_RCAL, MFM_COMMAND); + while (inw(MFM_STATUS) & STAT_BSY); + } + status = inw(MFM_STATUS); + DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8); + + while (len > 0) { + outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT); + len -= 2; + cmdb += 2; + } + status = inw(MFM_STATUS); + DBG("issue_command: status before command issue: %02X:\n ", status >> 8); + + outw(command, MFM_COMMAND); + status = inw(MFM_STATUS); + DBG("issue_command: status immediatly after command issue: %02X:\n ", status >> 8); +} + +static void wait_for_completion(void) +{ + while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY); +} + +static void wait_for_command_end(void) +{ + int i; + + while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED)); + + for (i = 0; i < 16;) { + int in; + in = inw(MFM_DATAIN); + result[i++] = in >> 8; + result[i++] = in; + } + outw (CMD_RCAL, MFM_COMMAND); +} + +/* ------------------------------------------------------------------------------------- */ + +static void mfm_rw_intr(void) +{ + int old_status; /* Holds status on entry, we read to see if the command just finished */ +#ifdef DEBUG + console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft); + print_status(); +#endif + + /* Now don't handle the error until BSY drops */ + if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) { + /* Something has gone wrong - lets try that again */ + outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + if (cont) { + DBG("mfm_rw_intr: DER/ABN err\n"); + cont->error(); + cont->redo(); + }; + return; + }; + + /* OK so what ever happend its not an error, now I reckon we are left between + a choice of command end or some data which is ready to be collected */ + /* I think we have to transfer data while the interrupt line is on and its + not any other type of interrupt */ + if (CURRENT->cmd == WRITE) { + extern void hdc63463_writedma(void); + if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) { + printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n"); + if (cont) { + cont->error(); + cont->redo(); + }; + return; + }; + hdc63463_writedma(); + } else { + extern void hdc63463_readdma(void); + if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) { + printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n"); + if (cont) { + cont->error(); + cont->redo(); + }; + return; + }; + DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr); + hdc63463_readdma(); + }; /* Read */ + + if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) { + /* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */ + /* Ah - well looking at the status its just when we get command end; so no problem */ + /*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n", + hdc63463_dataptr,Copy_buffer+256); + print_status(); */ + } else { + Sectors256LeftInCurrent--; + Copy_buffer += 256; + Copy_Sector++; + + /* We have come to the end of this request */ + if (!Sectors256LeftInCurrent) { + DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n", + CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors); + + CURRENT->nr_sectors -= CURRENT->current_nr_sectors; + CURRENT->sector += CURRENT->current_nr_sectors; + SectorsLeftInRequest -= CURRENT->current_nr_sectors; + + end_request(1); + if (SectorsLeftInRequest) { + hdc63463_dataptr = (unsigned int) CURRENT->buffer; + Copy_buffer = CURRENT->buffer; + Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2; + errors = &(CURRENT->errors); + /* These should match the present calculations of the next logical sector + on the device + Copy_Sector=CURRENT->sector*2; */ + + if (Copy_Sector != CURRENT->sector * 2) +#ifdef DEBUG + /*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n", + Copy_Sector, CURRENT->sector * 2); +#else + printk("mfm: Copy_Sector mismatch! Eek!\n"); +#endif + }; /* CURRENT */ + }; /* Sectors256LeftInCurrent */ + }; + + old_status = mfm_status; + mfm_status = inw(MFM_STATUS); + if (mfm_status & (STAT_DER | STAT_ABN)) { + /* Something has gone wrong - lets try that again */ + if (cont) { + DBG("mfm_rw_intr: DER/ABN error\n"); + cont->error(); + cont->redo(); + }; + return; + }; + + /* If this code wasn't entered due to command_end but there is + now a command end we must read the command results out. If it was + entered like this then mfm_interrupt_handler would have done the + job. */ + if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) && + ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) { + int len = 0; + while (len < 16) { + int in; + in = inw(MFM_DATAIN); + result[len++] = in >> 8; + result[len++] = in; + }; + }; /* Result read */ + + /*console_printf ("mfm_rw_intr nearexit [%02X]\n", inb(mfm_IRQPollLoc)); */ + + /* If end of command move on */ + if (mfm_status & (STAT_CED)) { + outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + /* End of command - trigger the next command */ + if (cont) { + cont->done(1); + } + DBG("mfm_rw_intr: returned from cont->done\n"); + } else { + /* Its going to generate another interrupt */ + SET_INTR(mfm_rw_intr); + }; +} + +static void mfm_setup_rw(void) +{ + DBG("setting up for rw...\n"); + + SET_INTR(mfm_rw_intr); + issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen); +} + +static void mfm_recal_intr(void) +{ +#ifdef DEBUG + console_printf("recal intr - status = "); + print_status(); +#endif + outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + if (mfm_status & (STAT_DER | STAT_ABN)) { + printk("recal failed\n"); + MFM_DRV_INFO.cylinder = NEED_2_RECAL; + if (cont) { + cont->error(); + cont->redo(); + } + return; + } + /* Thats seek end - we are finished */ + if (mfm_status & STAT_SED) { + issue_command(CMD_POD, NULL, 0); + MFM_DRV_INFO.cylinder = 0; + mfm_seek(); + return; + } + /* Command end without seek end (see data sheet p.20) for parallel seek + - we have to send a POL command to wait for the seek */ + if (mfm_status & STAT_CED) { + SET_INTR(mfm_recal_intr); + issue_command(CMD_POL, NULL, 0); + return; + } + printk("recal: unknown status\n"); +} + +static void mfm_seek_intr(void) +{ +#ifdef DEBUG + console_printf("seek intr - status = "); + print_status(); +#endif + outw(CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + if (mfm_status & (STAT_DER | STAT_ABN)) { + printk("seek failed\n"); + MFM_DRV_INFO.cylinder = NEED_2_RECAL; + if (cont) { + cont->error(); + cont->redo(); + } + return; + } + if (mfm_status & STAT_SED) { + issue_command(CMD_POD, NULL, 0); + MFM_DRV_INFO.cylinder = raw_cmd.cylinder; + mfm_seek(); + return; + } + if (mfm_status & STAT_CED) { + SET_INTR(mfm_seek_intr); + issue_command(CMD_POL, NULL, 0); + return; + } + printk("seek: unknown status\n"); +} + +/* IDEA2 seems to work better - its what RiscOS sets my + * disc to - on its SECOND call to specify! + */ +#define IDEA2 +#ifndef IDEA2 +#define SPEC_SL 0x16 +#define SPEC_SH 0xa9 /* Step pulse high=21, Record Length=001 (256 bytes) */ +#else +#define SPEC_SL 0x00 /* OM2 - SL - step pulse low */ +#define SPEC_SH 0x21 /* Step pulse high=4, Record Length=001 (256 bytes) */ +#endif + +static void mfm_setupspecify (int drive, unsigned char *cmdb) +{ + cmdb[0] = 0x1f; /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */ + cmdb[1] = 0xc3; /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */ + cmdb[2] = SPEC_SL; /* OM2 - SL - step pulse low */ + cmdb[3] = (number_mfm_drives == 1) ? 0x02 : 0x06; /* 1 or 2 drives */ + cmdb[4] = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */ + cmdb[5] = mfm_info[drive].cylinders - 1; /* low part of number of cylinders */ + cmdb[6] = mfm_info[drive].heads - 1; /* Number of heads */ + cmdb[7] = mfm_info[drive].sectors - 1; /* Number of sectors */ + cmdb[8] = SPEC_SH; + cmdb[9] = 0x0a; /* gap length 1 */ + cmdb[10] = 0x0d; /* gap length 2 */ + cmdb[11] = 0x0c; /* gap length 3 */ + cmdb[12] = (mfm_info[drive].precomp - 1) >> 8; /* pre comp cylinder */ + cmdb[13] = mfm_info[drive].precomp - 1; + cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8; /* Low current cylinder */ + cmdb[15] = mfm_info[drive].lowcurrent - 1; +} + +static void mfm_specify (void) +{ + unsigned char cmdb[16]; + + DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive); + mfm_setupspecify (raw_cmd.dev, cmdb); + + issue_command (CMD_SPC, cmdb, 16); + /* Ensure that we will do another specify if we move to the other drive */ + lastspecifieddrive = raw_cmd.dev; + wait_for_completion(); +} + +static void mfm_seek(void) +{ + unsigned char cmdb[4]; + + DBG("seeking...\n"); + if (MFM_DRV_INFO.cylinder < 0) { + SET_INTR(mfm_recal_intr); + DBG("mfm_seek: about to call specify\n"); + mfm_specify (); /* DAG added this */ + + cmdb[0] = raw_cmd.dev + 1; + cmdb[1] = 0; + + issue_command(CMD_RCLB, cmdb, 2); + return; + } + if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) { + cmdb[0] = raw_cmd.dev + 1; + cmdb[1] = 0; /* raw_cmd.head; DAG: My data sheet says this should be 0 */ + cmdb[2] = raw_cmd.cylinder >> 8; + cmdb[3] = raw_cmd.cylinder; + + SET_INTR(mfm_seek_intr); + issue_command(CMD_SEK, cmdb, 4); + } else + mfm_setup_rw(); +} + +static void mfm_initialise(void) +{ + DBG("init...\n"); + mfm_seek(); +} + +static void request_done(int uptodate) +{ + DBG("mfm:request_done\n"); + if (uptodate) { + unsigned char block[2] = {0, 0}; + + /* Apparently worked - lets check bytes left to DMA */ + if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) { + printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256); + end_request(0); + Busy = 0; + }; + /* Potentially this means that we've done; but we might be doing + a partial access, (over two cylinders) or we may have a number + of fragments in an image file. First lets deal with partial accesss + */ + if (PartFragRead) { + /* Yep - a partial access */ + + /* and issue the remainder */ + issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT); + return; + } + + /* ah well - perhaps there is another fragment to go */ + + /* Increment pointers/counts to start of next fragment */ + if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n"); + + /* No - its the end of the line */ + /* end_request's should have happened at the end of sector DMAs */ + /* Turns Drive LEDs off - may slow it down? */ + if (!CURRENT) + issue_command(CMD_CKV, block, 2); + + Busy = 0; + DBG("request_done: About to mfm_request\n"); + /* Next one please */ + mfm_request(); /* Moved from mfm_rw_intr */ + DBG("request_done: returned from mfm_request\n"); + } else { + printk("mfm:request_done: update=0\n"); + end_request(0); + Busy = 0; + } +} + +static void error_handler(void) +{ + printk("error detected... status = "); + print_status(); + (*errors)++; + if (*errors > MFM_DRV_INFO.errors.abort) + cont->done(0); + if (*errors > MFM_DRV_INFO.errors.recal) + MFM_DRV_INFO.cylinder = NEED_2_RECAL; +} + +static void rw_interrupt(void) +{ + printk("rw_interrupt\n"); +} + +static struct cont rw_cont = +{ + rw_interrupt, + error_handler, + mfm_rerequest, + request_done +}; + +/* + * Actually gets round to issuing the request - note everything at this + * point is in 256 byte sectors not Linux 512 byte blocks + */ +static void issue_request(int dev, unsigned int block, unsigned int nsect, + struct request *req) +{ + int track, start_head, start_sector; + int sectors_to_next_cyl; + + dev >>= 6; + + track = block / mfm_info[dev].sectors; + start_sector = block % mfm_info[dev].sectors; + start_head = track % mfm_info[dev].heads; + + /* First get the number of whole tracks which are free before the next + track */ + sectors_to_next_cyl = (mfm_info[dev].heads - (start_head + 1)) * mfm_info[dev].sectors; + /* Then add in the number of sectors left on this track */ + sectors_to_next_cyl += (mfm_info[dev].sectors - start_sector); + + DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", mfm_info[dev].sectors, track); + + raw_cmd.dev = dev; + raw_cmd.sector = start_sector; + raw_cmd.head = start_head; + raw_cmd.cylinder = track / mfm_info[dev].heads; + raw_cmd.cmdtype = CURRENT->cmd; + raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD; + raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */ + raw_cmd.cmddata[1] = raw_cmd.head; + raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8; + raw_cmd.cmddata[3] = raw_cmd.cylinder; + raw_cmd.cmddata[4] = raw_cmd.head; + raw_cmd.cmddata[5] = raw_cmd.sector; + + /* Was == and worked - how the heck??? */ + if (lastspecifieddrive != raw_cmd.dev) + mfm_specify (); + + if (nsect <= sectors_to_next_cyl) { + raw_cmd.cmddata[6] = nsect >> 8; + raw_cmd.cmddata[7] = nsect; + PartFragRead = 0; /* All in one */ + PartFragRead_SectorsLeft = 0; /* Must set this - used in DMA calcs */ + } else { + raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8; + raw_cmd.cmddata[7] = sectors_to_next_cyl; + PartFragRead = sectors_to_next_cyl; /* only do this many this time */ + PartFragRead_RestartBlock = block + sectors_to_next_cyl; /* Where to restart from */ + PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl; + } + raw_cmd.cmdlen = 8; + + /* Setup DMA pointers */ + hdc63463_dataptr = (unsigned int) Copy_buffer; + hdc63463_dataleft = nsect * 256; /* Better way? */ + + DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n", + raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ", + raw_cmd.cylinder, + raw_cmd.head, + raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT); + + cont = &rw_cont; + errors = &(CURRENT->errors); +#if 0 + mfm_tq.routine = (void (*)(void *)) mfm_initialise; + queue_task(&mfm_tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#else + mfm_initialise(); +#endif +} /* issue_request */ + +/* + * Called when an error has just happened - need to trick mfm_request + * into thinking we weren't busy + * + * Turn off ints - mfm_request expects them this way + */ +static void mfm_rerequest(void) +{ + DBG("mfm_rerequest\n"); + cli(); + Busy = 0; + mfm_request(); +} + +static void mfm_request(void) +{ + DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy); + + if (!CURRENT) { + DBG("mfm_request: Exited due to NULL Current 1\n"); + return; + } + + if (CURRENT->rq_status == RQ_INACTIVE) { + /* Hmm - seems to be happening a lot on 1.3.45 */ + /*console_printf("mfm_request: Exited due to INACTIVE Current\n"); */ + return; + } + + /* If we are still processing then return; we will get called again */ + if (Busy) { + /* Again seems to be common in 1.3.45 */ + /*DBG*/printk("mfm_request: Exiting due to busy\n"); + return; + } + Busy = 1; + + while (1) { + unsigned int dev, block, nsect; + + DBG("mfm_request: loop start\n"); + sti(); + + DBG("mfm_request: before INIT_REQUEST\n"); + + if (!CURRENT) { + printk("mfm_request: Exiting due to !CURRENT (pre)\n"); + CLEAR_INTR; + Busy = 0; + return; + }; + + INIT_REQUEST; + + DBG("mfm_request: before arg extraction\n"); + + dev = MINOR(CURRENT->rq_dev); + block = CURRENT->sector; + nsect = CURRENT->nr_sectors; +#ifdef DEBUG + /*if ((dev>>6)==1) */ console_printf("mfm_request: raw vals: dev=%d (block=512 bytes) block=%d nblocks=%d\n", dev, block, nsect); +#endif + if (dev >= (mfm_drives << 6) || + block >= mfm[dev].nr_sects || ((block+nsect) > mfm[dev].nr_sects)) { + if (dev >= (mfm_drives << 6)) + printk("mfm: bad minor number: device=%s\n", kdevname(CURRENT->rq_dev)); + else + printk("mfm%c: bad access: block=%d, count=%d, nr_sects=%ld\n", (dev >> 6)+'a', + block, nsect, mfm[dev].nr_sects); + printk("mfm: continue 1\n"); + end_request(0); + Busy = 0; + continue; + } + + block += mfm[dev].start_sect; + + /* DAG: Linux doesn't cope with this - even though it has an array telling + it the hardware block size - silly */ + block <<= 1; /* Now in 256 byte sectors */ + nsect <<= 1; /* Ditto */ + + SectorsLeftInRequest = nsect >> 1; + Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2; + Copy_buffer = CURRENT->buffer; + Copy_Sector = CURRENT->sector << 1; + + DBG("mfm_request: block after offset=%d\n", block); + + if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) { + printk("unknown mfm-command %d\n", CURRENT->cmd); + end_request(0); + Busy = 0; + printk("mfm: continue 4\n"); + continue; + } + issue_request(dev, block, nsect, CURRENT); + + break; + } + DBG("mfm_request: Dropping out bottom\n"); +} + +static void do_mfm_request(void) +{ + DBG("do_mfm_request: about to mfm_request\n"); + mfm_request(); +} + +static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs) +{ + void (*handler) (void) = DEVICE_INTR; + + CLEAR_INTR; + + DBG("mfm_interrupt_handler (handler=0x%p)\n", handler); + + mfm_status = inw(MFM_STATUS); + + /* If CPR (Command Parameter Reject) and not busy it means that the command + has some return message to give us */ + if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) { + int len = 0; + while (len < 16) { + int in; + in = inw(MFM_DATAIN); + result[len++] = in >> 8; + result[len++] = in; + } + } + if (handler) { + handler(); + return; + } + outw (CMD_RCAL, MFM_COMMAND); /* Clear interrupt condition */ + printk ("mfm: unexpected interrupt - status = "); + print_status (); + while (1); +} + + + + + +/* + * Tell the user about the drive if we decided it exists. Also, + * set the size of the drive. + */ +static void mfm_geometry (int drive) +{ + if (mfm_info[drive].cylinders) + printk ("mfm%c: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n", 'a' + drive, + mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 4096, + mfm_info[drive].cylinders, mfm_info[drive].heads, mfm_info[drive].sectors, + mfm_info[drive].lowcurrent, mfm_info[drive].precomp); + mfm[drive << 6].start_sect = 0; + mfm[drive << 6].nr_sects = mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 2; +} + +#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT +/* + * Attempt to detect a drive and find its geometry. The drive has already been + * specified... + * + * We first recalibrate the disk, then try to probe sectors, heads and then + * cylinders. NOTE! the cylinder probe may break drives. The xd disk driver + * does something along these lines, so I assume that most drives are up to + * this mistreatment... + */ +static int mfm_detectdrive (int drive) +{ + unsigned int mingeo[3], maxgeo[3]; + unsigned int attribute, need_recal = 1; + unsigned char cmdb[8]; + + memset (mingeo, 0, sizeof (mingeo)); + maxgeo[0] = mfm_info[drive].sectors; + maxgeo[1] = mfm_info[drive].heads; + maxgeo[2] = mfm_info[drive].cylinders; + + cmdb[0] = drive + 1; + cmdb[6] = 0; + cmdb[7] = 1; + for (attribute = 0; attribute < 3; attribute++) { + while (mingeo[attribute] != maxgeo[attribute]) { + unsigned int variable; + + variable = (maxgeo[attribute] + mingeo[attribute]) >> 1; + cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0; + + if (need_recal) { + int tries = 5; + + do { + issue_command (CMD_RCLB, cmdb, 2); + wait_for_completion (); + wait_for_command_end (); + if (result[1] == 0x20) + break; + } while (result[1] && --tries); + if (result[1]) { + outw (CMD_RCAL, MFM_COMMAND); + return 0; + } + need_recal = 0; + } + + switch (attribute) { + case 0: + cmdb[5] = variable; + issue_command (CMD_CMPD, cmdb, 8); + break; + case 1: + cmdb[1] = variable; + cmdb[4] = variable; + issue_command (CMD_CMPD, cmdb, 8); + break; + case 2: + cmdb[2] = variable >> 8; + cmdb[3] = variable; + issue_command (CMD_SEK, cmdb, 4); + break; + } + wait_for_completion (); + wait_for_command_end (); + + switch (result[1]) { + case 0x00: + case 0x50: + mingeo[attribute] = variable + 1; + break; + + case 0x20: + outw (CMD_RCAL, MFM_COMMAND); + return 0; + + case 0x24: + need_recal = 1; + default: + maxgeo[attribute] = variable; + break; + } + } + } + mfm_info[drive].cylinders = mingeo[2]; + mfm_info[drive].lowcurrent = mingeo[2]; + mfm_info[drive].precomp = mingeo[2] / 2; + mfm_info[drive].heads = mingeo[1]; + mfm_info[drive].sectors = mingeo[0]; + outw (CMD_RCAL, MFM_COMMAND); + return 1; +} +#endif + +/* + * Initialise all drive information for this controller. + */ +static int mfm_initdrives(void) +{ + int drive; + + if (number_mfm_drives > MFM_MAXDRIVES) { + number_mfm_drives = MFM_MAXDRIVES; + printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n"); + } + + for (drive = 0; drive < number_mfm_drives; drive++) { + mfm_info[drive].lowcurrent = 1; + mfm_info[drive].precomp = 1; + mfm_info[drive].cylinder = -1; + mfm_info[drive].errors.recal = 0; + mfm_info[drive].errors.report = 0; + mfm_info[drive].errors.abort = 4; + +#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT + mfm_info[drive].cylinders = 1024; + mfm_info[drive].heads = 8; + mfm_info[drive].sectors = 64; + { + unsigned char cmdb[16]; + + mfm_setupspecify (drive, cmdb); + cmdb[1] &= ~0x81; + issue_command (CMD_SPC, cmdb, 16); + wait_for_completion (); + if (!mfm_detectdrive (drive)) { + mfm_info[drive].cylinders = 0; + mfm_info[drive].heads = 0; + mfm_info[drive].sectors = 0; + } + cmdb[0] = cmdb[1] = 0; + issue_command (CMD_CKV, cmdb, 2); + } +#else + mfm_info[drive].cylinders = 1; /* its going to have to figure it out from the partition info */ + mfm_info[drive].heads = 4; + mfm_info[drive].sectors = 32; +#endif + } + return number_mfm_drives; +} + + + +/* + * The 'front' end of the mfm driver follows... + */ + +static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) +{ + struct hd_geometry *geo = (struct hd_geometry *) arg; + kdev_t dev; + int device, major, minor, err; + + if (!inode || !(dev = inode->i_rdev)) + return -EINVAL; + + major = MAJOR(dev); + minor = MINOR(dev); + + device = DEVICE_NR(MINOR(inode->i_rdev)), err; + if (device >= mfm_drives) + return -EINVAL; + + switch (cmd) { + case HDIO_GETGEO: + if (!arg) + return -EINVAL; + if (put_user (mfm_info[device].heads, &geo->heads)) + return -EFAULT; + if (put_user (mfm_info[device].sectors, &geo->sectors)) + return -EFAULT; + if (put_user (mfm_info[device].cylinders, &geo->cylinders)) + return -EFAULT; + if (put_user (mfm[minor].start_sect, &geo->start)) + return -EFAULT; + return 0; + + case BLKFLSBUF: + if (!suser()) + return -EACCES; + fsync_dev(dev); + invalidate_buffers(dev); + return 0; + + case BLKRASET: + if (!suser()) + return -EACCES; + if (arg > 0xff) + return -EINVAL; + read_ahead[major] = arg; + return 0; + + case BLKRAGET: + return put_user(read_ahead[major], (long *)arg); + + case BLKGETSIZE: + return put_user (mfm[minor].nr_sects, (long *)arg); + + case BLKFRASET: + if (!suser()) + return -EACCES; + max_readahead[major][minor] = arg; + return 0; + + case BLKFRAGET: + return put_user(max_readahead[major][minor], (long *) arg); + + case BLKSECTGET: + return put_user(max_sectors[major][minor], (long *) arg); + + case BLKRRPART: + if (!suser()) + return -EACCES; + return mfm_reread_partitions(dev); + + RO_IOCTLS(dev, arg); + + default: + return -EINVAL; + } +} + +static int mfm_open(struct inode *inode, struct file *file) +{ + int dev = DEVICE_NR(MINOR(inode->i_rdev)); + + if (dev >= mfm_drives) + return -ENODEV; + + MOD_INC_USE_COUNT; + while (mfm_info[dev].busy) + sleep_on (&mfm_wait_open); + + mfm_info[dev].access_count++; + return 0; +} + +/* + * Releasing a block device means we sync() it, so that it can safely + * be forgotten about... + */ +static int mfm_release(struct inode *inode, struct file *file) +{ + fsync_dev(inode->i_rdev); + mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--; + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * This is to handle various kernel command line parameters + * specific to this driver. + */ +void mfm_setup(char *str, int *ints) +{ + return; +} + +/* + * Set the CHS from the ADFS boot block if it is present. This is not ideal + * since if there are any non-ADFS partitions on the disk, this won't work! + * Hence, I want to get rid of this... + */ +void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads, + unsigned long discsize, unsigned int secsize) +{ + int drive = MINOR(dev) >> 6; + + if (mfm_info[drive].cylinders == 1) { + mfm_info[drive].sectors = secsptrack; + mfm_info[drive].heads = heads; + mfm_info[drive].cylinders = discsize / (secsptrack * heads * secsize); + + if ((heads < 1) || (mfm_info[drive].cylinders > 1024)) { + printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + (dev >> 6)); + + /* These values are fairly arbitary, but are there so that if your + * lucky you can pick apart your disc to find out what is going on - + * I reckon these figures won't hurt MOST drives + */ + mfm_info[drive].sectors = 32; + mfm_info[drive].heads = 4; + mfm_info[drive].cylinders = 512; + } + if (raw_cmd.dev == drive) + mfm_specify (); + mfm_geometry (drive); + } +} + +static void mfm_geninit (struct gendisk *gdev); + +static struct gendisk mfm_gendisk = { + MAJOR_NR, /* Major number */ + "mfm", /* Major name */ + 6, /* Bits to shift to get real from partition */ + 1 << 6, /* Number of partitions per real */ + MFM_MAXDRIVES, /* maximum number of real */ + mfm_geninit, /* init function */ + mfm, /* hd struct */ + mfm_sizes, /* block sizes */ + 0, /* number */ + (void *) mfm_info, /* internal */ + NULL /* next */ +}; + +static void mfm_geninit (struct gendisk *gdev) +{ + int i; + + mfm_drives = mfm_initdrives(); + + printk("mfm: detected %d hard drive%s\n", mfm_drives, mfm_drives == 1 ? "" : "s"); + gdev->nr_real = mfm_drives; + + for (i = 0; i < mfm_drives; i++) + mfm_geometry (i); + + if (request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL)) + printk("mfm: unable to get IRQ%d\n", mfm_irq); + + if (mfm_irqenable) + outw(0x80, mfm_irqenable); /* Required to enable IRQs from MFM podule */ + + for (i = 0; i < (MFM_MAXDRIVES << 6); i++) { + mfm_blocksizes[i] = 1024; /* Can't increase this - if you do all hell breaks loose */ + mfm_sectsizes[i] = 512; + } + blksize_size[MAJOR_NR] = mfm_blocksizes; + hardsect_size[MAJOR_NR] = mfm_sectsizes; +} + +static struct file_operations mfm_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* poll */ + mfm_ioctl, /* ioctl */ + NULL, /* mmap */ + mfm_open, /* open */ + mfm_release, /* release */ + block_fsync, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL /* revalidate */ +}; + + +static struct expansion_card *ecs; + +/* + * See if there is a controller at the address presently at mfm_addr + * + * We check to see if the controller is busy - if it is, we abort it first, + * and check that the chip is no longer busy after at least 180 clock cycles. + * We then issue a command and check that the BSY or CPR bits are set. + */ +static int mfm_probecontroller (unsigned int mfm_addr) +{ + if (check_region (mfm_addr, 10)) + return 0; + + if (inw (MFM_STATUS) & STAT_BSY) { + outw (CMD_ABT, MFM_COMMAND); + udelay (50); + if (inw (MFM_STATUS) & STAT_BSY) + return 0; + } + + if (inw (MFM_STATUS) & STAT_CED) + outw (CMD_RCAL, MFM_COMMAND); + + outw (CMD_SEK, MFM_COMMAND); + + if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) { + unsigned int count = 2000; + while (inw (MFM_STATUS) & STAT_BSY) { + udelay (500); + if (!--count) + return 0; + } + + outw (CMD_RCAL, MFM_COMMAND); + } + return 1; +} + +/* + * Look for a MFM controller - first check the motherboard, then the podules + * The podules have an extra interrupt enable that needs to be played with + * + * The HDC is accessed at MEDIUM IOC speeds. + */ +int mfm_init (void) +{ + unsigned char irqmask; + + if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) { + printk("mfm_init: unable to get major number %d\n", MAJOR_NR); + return -1; + } + + if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) { + mfm_addr = ONBOARD_MFM_ADDRESS; + mfm_IRQPollLoc = IOC_IRQSTATB; + mfm_irqenable = 0; + mfm_irq = IRQ_HARDDISK; + irqmask = 0x08; /* IL3 pin */ + } else { + ecs = ecard_find(0, mfm_cids); + if (!ecs) { + mfm_addr = 0; + return -1; + } + + mfm_addr = ecard_address(ecs, ECARD_IOC, ECARD_MEDIUM) + 0x800; + mfm_IRQPollLoc = mfm_addr + 0x400; + mfm_irqenable = mfm_IRQPollLoc; + mfm_irq = ecs->irq; + irqmask = 0x08; + + ecard_claim(ecs); + } + + printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq); + request_region (mfm_addr, 10, "mfm"); + + /* Stuff for the assembler routines to get to */ + hdc63463_baseaddress = ioaddr(mfm_addr); + hdc63463_irqpolladdress = ioaddr(mfm_IRQPollLoc); + hdc63463_irqpollmask = irqmask; + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB?) read ahread */ + +#ifndef MODULE + mfm_gendisk.next = gendisk_head; + gendisk_head = &mfm_gendisk; +#endif + + Busy = 0; + lastspecifieddrive = -1; + + return 0; +} + +/* + * This routine is called to flush all partitions and partition tables + * for a changed MFM disk, and then re-read the new partition table. + * If we are revalidating due to an ioctl, we have USAGE == 1. + */ +static int mfm_reread_partitions(kdev_t dev) +{ + unsigned int start, i, maxp, target = DEVICE_NR(MINOR(dev)); + unsigned long flags; + + save_flags_cli(flags); + if (mfm_info[target].busy || mfm_info[target].access_count > 1) { + restore_flags (flags); + return -EBUSY; + } + mfm_info[target].busy = 1; + restore_flags (flags); + + maxp = mfm_gendisk.max_p; + start = target << mfm_gendisk.minor_shift; + + for (i = maxp - 1; i >= 0; i--) { + int minor = start + i; + kdev_t devi = MKDEV(MAJOR_NR, minor); + struct super_block *sb = get_super(devi); + + sync_dev (devi); + if (sb) + invalidate_inodes (sb); + invalidate_buffers (devi); + + mfm_gendisk.part[minor].start_sect = 0; + mfm_gendisk.part[minor].nr_sects = 0; + } + + mfm_gendisk.part[start].nr_sects = mfm_info[target].heads * + mfm_info[target].cylinders * mfm_info[target].sectors / 2; + + resetup_one_dev(&mfm_gendisk, target); + + mfm_info[target].busy = 0; + wake_up (&mfm_wait_open); + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + int ret; + ret = mfm_init(); + if (!ret) + mfm_geninit(&mfm_gendisk); + return ret; +} + +void cleanup_module(void) +{ + if (ecs && mfm_irqenable) + outw (0, mfm_irqenable); /* Required to enable IRQs from MFM podule */ + free_irq(mfm_irq, NULL); + unregister_blkdev(MAJOR_NR, "mfm"); + if (ecs) + ecard_release(ecs); + if (mfm_addr) + release_region(mfm_addr, 10); +} +#endif diff -ur --new-file old/linux/drivers/acorn/net/Config.in new/linux/drivers/acorn/net/Config.in --- old/linux/drivers/acorn/net/Config.in Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/net/Config.in Tue Feb 17 00:49:47 1998 @@ -0,0 +1,7 @@ +# +# Acorn Network device configuration +# These are for Acorn's Expansion card network interfaces +# +tristate 'Acorn Ether1 (82586) support' CONFIG_ARM_ETHER1 +tristate 'Acorn/ANT Ether3 (NQ8005) support' CONFIG_ARM_ETHER3 +tristate 'I-cubed EtherH (NS8390) support' CONFIG_ARM_ETHERH diff -ur --new-file old/linux/drivers/acorn/net/Makefile new/linux/drivers/acorn/net/Makefile --- old/linux/drivers/acorn/net/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/net/Makefile Tue Feb 17 00:49:47 1998 @@ -0,0 +1,35 @@ +# File: drivers/acorn/net/Makefile +# +# Makefile for the Acorn ethercard network device drivers +# + +L_TARGET := acorn-net.a +L_OBJS := net-probe.o +M_OBJS := +MOD_LIST_NAME := ACORN_NET_MODULES + +ifeq ($(CONFIG_ARM_ETHER1),y) + L_OBJS += ether1.o +else + ifeq ($(CONFIG_ARM_ETHER1),m) + M_OBJS += ether1.o + endif +endif + +ifeq ($(CONFIG_ARM_ETHER3),y) + L_OBJS += ether3.o +else + ifeq ($(CONFIG_ARM_ETHER3),m) + M_OBJS += ether3.o + endif +endif + +ifeq ($(CONFIG_ARM_ETHERH),y) + L_OBJS += etherh.o +else + ifeq ($(CONFIG_ARM_ETHERH),m) + M_OBJS += etherh.o + endif +endif + +include $(TOPDIR)/Rules.make diff -ur --new-file old/linux/drivers/acorn/net/ether1.c new/linux/drivers/acorn/net/ether1.c --- old/linux/drivers/acorn/net/ether1.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/net/ether1.c Tue Feb 17 00:49:47 1998 @@ -0,0 +1,1241 @@ +/* + * linux/arch/arm/drivers/net/ether1.c + * + * (C) Copyright 1996,1997,1998 Russell King + * + * Acorn ether1 driver (82586 chip) + * for Acorn machines + */ + +/* + * We basically keep two queues in the cards memory - one for transmit + * and one for receive. Each has a head and a tail. The head is where + * we/the chip adds packets to be transmitted/received, and the tail + * is where the transmitter has got to/where the receiver will stop. + * Both of these queues are circular, and since the chip is running + * all the time, we have to be careful when we modify the pointers etc + * so that the buffer memory contents is valid all the time. + */ + +/* + * Change log: + * 1.00 RMK Released + * 1.01 RMK 19/03/1996 Transfers the last odd byte onto/off of the card now. + * 1.02 RMK 25/05/1997 Added code to restart RU if it goes not ready + * 1.03 RMK 14/09/1997 Cleaned up the handling of a reset during the TX interrupt. + * Should prevent lockup. + * 1.04 RMK 17/09/1997 Added more info when initialsation of chip goes wrong. + * TDR now only reports failure when chip reports non-zero + * TDR time-distance. + * 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define __ETHER1_C +#include "ether1.h" + +static unsigned int net_debug = NET_DEBUG; + +#define struct ether1_priv *priv = (struct ether1_priv *)dev->priv \ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv + +#define BUFFER_SIZE 0x10000 +#define TX_AREA_START 0x00100 +#define TX_AREA_END 0x05000 +#define RX_AREA_START 0x05000 +#define RX_AREA_END 0x0fc00 + +#define tx_done(dev) 0 +/* ------------------------------------------------------------------------- */ +static char *version = "ether1 ethernet driver (c) 1995 Russell King v1.05\n"; + +#define BUS_16 16 +#define BUS_8 8 + +static const card_ids ether1_cids[] = { + { MANU_ACORN, PROD_ACORN_ETHER1 }, + { 0xffff, 0xffff } +}; + +/* ------------------------------------------------------------------------- */ + +#define DISABLEIRQS 1 +#define NORMALIRQS 0 + +#define ether1_inw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs) +#define ether1_outw(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs) + +static inline unsigned short ether1_inw_p (struct device *dev, int addr, int svflgs) +{ + unsigned long flags; + unsigned short ret; + + if (svflgs) { + save_flags_cli (flags); + } + outb (addr >> 12, REG_PAGE); + ret = inw (ETHER1_RAM + ((addr & 4095) >> 1)); + if (svflgs) + restore_flags (flags); + return ret; +} + +static inline void ether1_outw_p (struct device *dev, unsigned short val, int addr, int svflgs) +{ + unsigned long flags; + + if (svflgs) { + save_flags_cli (flags); + } + outb (addr >> 12, REG_PAGE); + outw (val, ETHER1_RAM + ((addr & 4095) >> 1)); + if (svflgs) + restore_flags (flags); +} + +/* + * Some inline assembler to allow fast transfers on to/off of the card. + * Since this driver depends on some features presented by the ARM + * specific architecture, and that you can't configure this driver + * without specifiing ARM mode, this is not a problem. + * + * This routine is essentially an optimised memcpy from the card's + * onboard RAM to kernel memory. + */ + +static inline void *ether1_inswb (unsigned int addr, void *data, unsigned int len) +{ + int used; + + addr = IO_BASE + (addr << 2); + + __asm__ __volatile__( + "subs %3, %3, #2 + bmi 2f +1: ldr %0, [%1], #4 + strb %0, [%2], #1 + mov %0, %0, lsr #8 + strb %0, [%2], #1 + subs %3, %3, #2 + bmi 2f + ldr %0, [%1], #4 + strb %0, [%2], #1 + mov %0, %0, lsr #8 + strb %0, [%2], #1 + subs %3, %3, #2 + bmi 2f + ldr %0, [%1], #4 + strb %0, [%2], #1 + mov %0, %0, lsr #8 + strb %0, [%2], #1 + subs %3, %3, #2 + bmi 2f + ldr %0, [%1], #4 + strb %0, [%2], #1 + mov %0, %0, lsr #8 + strb %0, [%2], #1 + subs %3, %3, #2 + bpl 1b +2: adds %3, %3, #1 + ldreqb %0, [%1] + streqb %0, [%2]" + : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) + : "1" (addr), "2" (data), "3" (len)); + + return data; +} + +static inline void *ether1_outswb (unsigned int addr, void *data, unsigned int len) +{ + int used; + + addr = IO_BASE + (addr << 2); + + __asm__ __volatile__( + "subs %3, %3, #2 + bmi 2f +1: ldr %0, [%2], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%1], #4 + subs %3, %3, #2 + bmi 2f + ldr %0, [%2], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%1], #4 + subs %3, %3, #2 + bmi 2f + ldr %0, [%2], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%1], #4 + subs %3, %3, #2 + bmi 2f + ldr %0, [%2], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%1], #4 + subs %3, %3, #2 + bpl 1b +2: adds %3, %3, #1 + ldreqb %0, [%2] + streqb %0, [%1]" + : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) + : "1" (addr), "2" (data), "3" (len)); + + return data; +} + + +static void ether1_writebuffer (struct device *dev, void *data, unsigned int start, unsigned int length) +{ + unsigned int page, thislen, offset; + offset = start & 4095; + + for (page = start >> 12; length; page++) + { + outb (page, REG_PAGE); + if (offset + length > 4096) + { + length -= 4096 - offset; + thislen = 4096 - offset; + } + else + { + thislen = length; + length = 0; + } + + data = ether1_outswb (ETHER1_RAM + (offset >> 1), data, thislen); + offset = 0; + } +} + +static void ether1_readbuffer (struct device *dev, void *data, unsigned int start, unsigned int length) +{ + unsigned int page, thislen, offset; + + offset = start & 4095; + + for (page = start >> 12; length; page++) + { + outb (page, REG_PAGE); + if (offset + length > 4096) + { + length -= 4096 - offset; + thislen = 4096 - offset; + } + else + { + thislen = length; + length = 0; + } + + data = ether1_inswb (ETHER1_RAM + (offset >> 1), data, thislen); + offset = 0; + } +} + +static int ether1_ramtest (struct device *dev, unsigned char byte) +{ + unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL); + int i, ret = BUFFER_SIZE; + int max_errors = 15; + int bad = -1; + int bad_start = 0; + + if (!buffer) + return 1; + + memset (buffer, byte, BUFFER_SIZE); + ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE); + memset (buffer, byte ^ 0xff, BUFFER_SIZE); + ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE); + + for (i = 0; i < BUFFER_SIZE; i++) + { + if (buffer[i] != byte) + { + if (max_errors >= 0 && bad != buffer[i]) + { + if (bad != -1) + printk ("\n"); + printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X", + dev->name, buffer[i], byte, i); + ret = -ENODEV; + max_errors --; + bad = buffer[i]; + bad_start = i; + } + } + else + { + if (bad != -1) + { + if (bad_start == i - 1) + printk ("\n"); + else + printk (" - 0x%04X\n", i - 1); + bad = -1; + } + } + } + + if (bad != -1) + printk (" - 0x%04X\n", BUFFER_SIZE); + kfree (buffer); + + return ret; +} + +static int ether1_reset (struct device *dev) +{ + outb (CTRL_RST|CTRL_ACK, REG_CONTROL); + return BUS_16; +} + +static int ether1_init_2 (struct device *dev) +{ + int i; + dev->mem_start = 0; + + i = ether1_ramtest (dev, 0x5a); + + if (i > 0) + i = ether1_ramtest (dev, 0x1e); + + if (i <= 0) + return -ENODEV; + + dev->mem_end = i; + return 0; +} + +/* + * These are the structures that are loaded into the ether RAM card to + * initialise the 82586 + */ + +/* at 0x0100 */ + +#define NOP_ADDR (TX_AREA_START) +#define NOP_SIZE (0x06) + +static nop_t init_nop = +{ + 0, + CMD_NOP, + NOP_ADDR +}; + +/* at 0x003a */ +#define TDR_ADDR (0x003a) +#define TDR_SIZE (0x08) +static tdr_t init_tdr = { + 0, + CMD_TDR | CMD_INTR, + NOP_ADDR, + 0 +}; + +/* at 0x002e */ +#define MC_ADDR (0x002e) +#define MC_SIZE (0x0c) +static mc_t init_mc = +{ + 0, + CMD_SETMULTICAST, + TDR_ADDR, + 0, + { { 0, } } +}; + +/* at 0x0022 */ +#define SA_ADDR (0x0022) +#define SA_SIZE (0x0c) +static sa_t init_sa = { + 0, + CMD_SETADDRESS, + MC_ADDR, + { 0, } +}; + +/* at 0x0010 */ +#define CFG_ADDR (0x0010) +#define CFG_SIZE (0x12) +static cfg_t init_cfg = { + 0, + CMD_CONFIG, + SA_ADDR, + 8, + 8, + CFG8_SRDY, + CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6), + 0, + 0x60, + 0, + CFG13_RETRY(15) | CFG13_SLOTH(2), + 0, +}; + +/* at 0x0000 */ +#define SCB_ADDR (0x0000) +#define SCB_SIZE (0x10) +static scb_t init_scb = { + 0, + SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX, + CFG_ADDR, + RX_AREA_START, + 0, + 0, + 0, + 0 +}; + +/* at 0xffee */ +#define ISCP_ADDR (0xffee) +#define ISCP_SIZE (0x08) +static iscp_t init_iscp = { + 1, + SCB_ADDR, + 0x0000, + 0x0000 +}; + +/* at 0xfff6 */ +#define SCP_ADDR (0xfff6) +#define SCP_SIZE (0x0a) +static scp_t init_scp = { + SCP_SY_16BBUS, + { 0, 0 }, + ISCP_ADDR, + 0 +}; + +#define RFD_SIZE (0x16) +static rfd_t init_rfd = { + 0, + 0, + 0, + 0, + { 0, }, + { 0, }, + 0 +}; + +#define RBD_SIZE (0x0a) +static rbd_t init_rbd = { + 0, + 0, + 0, + 0, + ETH_FRAME_LEN + 8 +}; + +#define TX_SIZE (0x08) +#define TBD_SIZE (0x08) + +static int ether1_init_for_open (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + int i, status, addr, next, next2; + int failures = 0; + + outb (CTRL_RST|CTRL_ACK, REG_CONTROL); + + for (i = 0; i < 6; i++) + init_sa.sa_addr[i] = dev->dev_addr[i]; + + /* load data structures into ether1 RAM */ + ether1_writebuffer (dev, &init_scp, SCP_ADDR, SCP_SIZE); + ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE); + ether1_writebuffer (dev, &init_scb, SCB_ADDR, SCB_SIZE); + ether1_writebuffer (dev, &init_cfg, CFG_ADDR, CFG_SIZE); + ether1_writebuffer (dev, &init_sa, SA_ADDR, SA_SIZE); + ether1_writebuffer (dev, &init_mc, MC_ADDR, MC_SIZE); + ether1_writebuffer (dev, &init_tdr, TDR_ADDR, TDR_SIZE); + ether1_writebuffer (dev, &init_nop, NOP_ADDR, NOP_SIZE); + + if (ether1_inw (dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) + { + printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n", + dev->name); + return 1; + } + + /* + * setup circularly linked list of { rfd, rbd, buffer }, with + * all rfds circularly linked, rbds circularly linked. + * First rfd is linked to scp, first rbd is linked to first + * rfd. Last rbd has a suspend command. + */ + + addr = RX_AREA_START; + + do + { + next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; + next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10; + + if (next2 >= RX_AREA_END) + { + next = RX_AREA_START; + init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND; + priv->rx_tail = addr; + } + else + init_rfd.rfd_command = 0; + if (addr == RX_AREA_START) + init_rfd.rfd_rbdoffset = addr + RFD_SIZE; + else + init_rfd.rfd_rbdoffset = 0; + init_rfd.rfd_link = next; + init_rbd.rbd_link = next + RFD_SIZE; + init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE; + + ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE); + ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE); + addr = next; + } + while (next2 < RX_AREA_END); + + priv->tx_link = NOP_ADDR; + priv->tx_head = NOP_ADDR + NOP_SIZE; + priv->tx_tail = TDR_ADDR; + priv->rx_head = RX_AREA_START; + + /* release reset & give 586 a prod */ + priv->resetting = 1; + priv->initialising = 1; + outb (CTRL_RST, REG_CONTROL); + outb (0, REG_CONTROL); + outb (CTRL_CA, REG_CONTROL); + + /* 586 should now unset iscp.busy */ + i = jiffies + HZ/2; + while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) + { + if (jiffies > i) + { + printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name); + return 1; + } + } + + /* check status of commands that we issued */ + i += HZ/10; + while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) + { + if (jiffies-i<0) + break; + } + + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) + { + printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status); + printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); + failures += 1; + } + + i += HZ/10; + while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) + { + if (jiffies-i<0) + break; + } + + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) + { + printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status); + printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); + failures += 1; + } + + i += HZ/10; + while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) + { + if (jiffies-i < 0) + break; + } + + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) + { + printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status); + printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); + failures += 1; + } + + i += HZ; + while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS)) & STAT_COMPLETE) == 0) + { + if (jiffies-i <0) + break; + } + + if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) + { + printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name); + printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS), + ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS)); + } + else + { + status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS); + if (status & TDR_XCVRPROB) + printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name); + else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) + { +#ifdef FANCY + printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name, + status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10, + (status & TDR_TIME) % 10); +#else + printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name, + status & TDR_SHORT ? "short" : "open", (status & TDR_TIME)); +#endif + } + } + + if (failures) + ether1_reset (dev); + return failures ? 1 : 0; +} + +static int ether1_probe1 (struct device *dev) +{ + static unsigned int version_printed = 0; + struct ether1_priv *priv; + int i; + + if (!dev->priv) + dev->priv = kmalloc (sizeof (struct ether1_priv), GFP_KERNEL); + + if (!dev->priv) + return 1; + + priv = (struct ether1_priv *)dev->priv; + memset (priv, 0, sizeof (struct ether1_priv)); + + if ((priv->bus_type = ether1_reset (dev)) == 0) + { + kfree (dev->priv); + return 1; + } + + if (net_debug && version_printed++ == 0) + printk (KERN_INFO "%s", version); + + printk (KERN_INFO "%s: ether1 found [%d, %04lx, %d]", dev->name, priv->bus_type, + dev->base_addr, dev->irq); + + request_region (dev->base_addr, 16, "ether1"); + request_region (dev->base_addr + 0x800, 4096, "ether1(ram)"); + + for (i = 0; i < 6; i++) + printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]); + + if (ether1_init_2 (dev)) + { + kfree (dev->priv); + return 1; + } + + dev->open = ether1_open; + dev->stop = ether1_close; + dev->hard_start_xmit= ether1_sendpacket; + dev->get_stats = ether1_getstats; + dev->set_multicast_list = ether1_setmulticastlist; + + /* Fill in the fields of the device structure with ethernet values */ + ether_setup (dev); + +#ifndef CLAIM_IRQ_AT_OPEN + if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) + { + kfree (dev->priv); + return -EAGAIN; + } +#endif + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static void ether1_addr (struct device *dev) +{ + int i; + + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inb (IDPROM_ADDRESS + i); +} + +int ether1_probe (struct device *dev) +{ +#ifndef MODULE + struct expansion_card *ec; + + if (!dev) + return ENODEV; + + ecard_startfind (); + if ((ec = ecard_find (0, ether1_cids)) == NULL) + return ENODEV; + + dev->base_addr = ecard_address (ec, ECARD_IOC, ECARD_FAST); + dev->irq = ec->irq; + + ecard_claim (ec); +#endif + ether1_addr (dev); + + if (ether1_probe1 (dev) == 0) + return 0; + return ENODEV; +} + +/* ------------------------------------------------------------------------- */ + +static int ether1_txalloc (struct device *dev, int size) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + int start, tail; + + size = (size + 1) & ~1; + tail = priv->tx_tail; + + if (priv->tx_head + size > TX_AREA_END) + { + if (tail > priv->tx_head) + return -1; + start = TX_AREA_START; + if (start + size > tail) + return -1; + priv->tx_head = start + size; + } + else + { + if (priv->tx_head < tail && (priv->tx_head + size) > tail) + return -1; + start = priv->tx_head; + priv->tx_head += size; + } + return start; +} + +static void ether1_restart (struct device *dev, char *reason) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + priv->stats.tx_errors ++; + + if (reason) + printk (KERN_WARNING "%s: %s - resetting device\n", dev->name, reason); + else + printk (" - resetting device\n"); + + ether1_reset (dev); + + dev->start = 0; + dev->tbusy = 0; + + if (ether1_init_for_open (dev)) + printk (KERN_ERR "%s: unable to restart interface\n", dev->name); + + dev->start = 1; +} + +static int ether1_open (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; +#ifdef CLAIM_IRQ_AT_OPEN + if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) + return -EAGAIN; +#endif + MOD_INC_USE_COUNT; + + memset (&priv->stats, 0, sizeof (struct enet_statistics)); + + if (ether1_init_for_open (dev)) + { +#ifdef CLAIM_IRQ_AT_OPEN + free_irq (dev->irq, dev); +#endif + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + return 0; +} + +static int ether1_sendpacket (struct sk_buff *skb, struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + + if (priv->restart) + ether1_restart (dev, NULL); + + if (dev->tbusy) + { + /* + * If we get here, some higher level has decided that we are broken. + * There should really be a "kick me" function call instead. + */ + int tickssofar = jiffies - dev->trans_start; + + if (tickssofar < 5) + return 1; + + /* Try to restart the adapter. */ + ether1_restart (dev, "transmit timeout, network cable problem?"); + 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); + else + { + int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; + unsigned long flags; + tx_t tx; + tbd_t tbd; + nop_t nop; + + /* + * insert packet followed by a nop + */ + txaddr = ether1_txalloc (dev, TX_SIZE); + tbdaddr = ether1_txalloc (dev, TBD_SIZE); + dataddr = ether1_txalloc (dev, len); + nopaddr = ether1_txalloc (dev, NOP_SIZE); + + tx.tx_status = 0; + tx.tx_command = CMD_TX | CMD_INTR; + tx.tx_link = nopaddr; + tx.tx_tbdoffset = tbdaddr; + tbd.tbd_opts = TBD_EOL | len; + tbd.tbd_link = I82586_NULL; + tbd.tbd_bufl = dataddr; + tbd.tbd_bufh = 0; + nop.nop_status = 0; + nop.nop_command = CMD_NOP; + nop.nop_link = nopaddr; + + save_flags_cli (flags); + ether1_writebuffer (dev, &tx, txaddr, TX_SIZE); + ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE); + ether1_writebuffer (dev, skb->data, dataddr, len); + ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE); + tmp = priv->tx_link; + priv->tx_link = nopaddr; + + /* now reset the previous nop pointer */ + ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS); + + restore_flags (flags); + + /* handle transmit */ + dev->trans_start = jiffies; + + /* check to see if we have room for a full sized ether frame */ + tmp = priv->tx_head; + tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); + priv->tx_head = tmp; + if (tst != -1) + dev->tbusy = 0; + } + dev_kfree_skb (skb, FREE_WRITE); + + return 0; +} + +static void ether1_xmit_done (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + nop_t nop; + int caddr, tst; + + caddr = priv->tx_tail; + +again: + ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); + + switch (nop.nop_command & CMD_MASK) + { + case CMD_TDR: + /* special case */ + if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) != (unsigned short)I82586_NULL) + { + ether1_outw (dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t, + scb_command, NORMALIRQS); + outb (CTRL_CA, REG_CONTROL); + } + priv->tx_tail = NOP_ADDR; + return; + + case CMD_NOP: + if (nop.nop_link == caddr) + { + if (priv->initialising == 0) + printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name); + else + priv->initialising = 0; + return; + } + if (caddr == nop.nop_link) + return; + caddr = nop.nop_link; + goto again; + + case CMD_TX: + if (nop.nop_status & STAT_COMPLETE) + break; + printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name); + priv->restart = 1; + return; + + default: + printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name, + nop.nop_command & CMD_MASK, caddr); + priv->restart = 1; + return; + } + + while (nop.nop_status & STAT_COMPLETE) + { + if (nop.nop_status & STAT_OK) + { + priv->stats.tx_packets ++; + priv->stats.collisions += (nop.nop_status & STAT_COLLISIONS); + } + else + { + priv->stats.tx_errors ++; + if (nop.nop_status & STAT_COLLAFTERTX) + priv->stats.collisions ++; + if (nop.nop_status & STAT_NOCARRIER) + priv->stats.tx_carrier_errors ++; + if (nop.nop_status & STAT_TXLOSTCTS) + printk (KERN_WARNING "%s: cts lost\n", dev->name); + if (nop.nop_status & STAT_TXSLOWDMA) + priv->stats.tx_fifo_errors ++; + if (nop.nop_status & STAT_COLLEXCESSIVE) + priv->stats.collisions += 16; + } + if (nop.nop_link == caddr) + { + printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name); + break; + } + + caddr = nop.nop_link; + ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); + if ((nop.nop_command & CMD_MASK) != CMD_NOP) + { + printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name); + break; + } + + if (caddr == nop.nop_link) + break; + + caddr = nop.nop_link; + ether1_readbuffer (dev, &nop, caddr, NOP_SIZE); + if ((nop.nop_command & CMD_MASK) != CMD_TX) + { + printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name); + break; + } + } + priv->tx_tail = caddr; + + caddr = priv->tx_head; + tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); + priv->tx_head = caddr; + if (tst != -1) + dev->tbusy = 0; + + mark_bh (NET_BH); +} + +static void ether1_recv_done (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + int status; + int nexttail, rbdaddr; + rbd_t rbd; + + do + { + status = ether1_inw (dev, priv->rx_head, rfd_t, rfd_status, NORMALIRQS); + if ((status & RFD_COMPLETE) == 0) + break; + + rbdaddr = ether1_inw (dev, priv->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS); + ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE); + + if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) + { + int length = rbd.rbd_status & RBD_ACNT; + struct sk_buff *skb; + + length = (length + 1) & ~1; + skb = dev_alloc_skb (length + 2); + + if (skb) + { + skb->dev = dev; + skb_reserve (skb, 2); + + ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length); + + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); + priv->stats.rx_packets ++; + } + else + priv->stats.rx_dropped ++; + } + else + { + printk (KERN_WARNING "%s: %s\n", dev->name, + (rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid"); + priv->stats.rx_dropped ++; + } + + nexttail = ether1_inw (dev, priv->rx_tail, rfd_t, rfd_link, NORMALIRQS); + /* nexttail should be rx_head */ + if (nexttail != priv->rx_head) + printk (KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n", + dev->name, nexttail, priv->rx_head); + ether1_outw (dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS); + ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_command, NORMALIRQS); + ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_status, NORMALIRQS); + ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS); + + priv->rx_tail = nexttail; + priv->rx_head = ether1_inw (dev, priv->rx_head, rfd_t, rfd_link, NORMALIRQS); + } + while (1); +} + +static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + int status; + + dev->interrupt = 1; + + status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS); + + if (status) + { + ether1_outw (dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX), + SCB_ADDR, scb_t, scb_command, NORMALIRQS); + outb (CTRL_CA | CTRL_ACK, REG_CONTROL); + if (status & SCB_STCX) + ether1_xmit_done (dev); + if (status & SCB_STCNA) + { + if (priv->resetting == 0) + printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name); + else + priv->resetting += 1; + if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS) != (unsigned short)I82586_NULL) + { + ether1_outw (dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS); + outb (CTRL_CA, REG_CONTROL); + } + if (priv->resetting == 2) + priv->resetting = 0; + } + if (status & SCB_STFR) + ether1_recv_done (dev); + + if (status & SCB_STRNR) + { + if (ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) + { + printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name); + ether1_outw (dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS); + outb (CTRL_CA, REG_CONTROL); + priv->stats.rx_dropped ++; /* we suspended due to lack of buffer space */ + } + else + printk (KERN_WARNING "%s: RU went not ready: %04X\n", dev->name, + ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS)); + printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset,NORMALIRQS)); + } + } + else + outb (CTRL_ACK, REG_CONTROL); + + dev->interrupt = 0; +} + +static int ether1_close (struct device *dev) +{ +#ifdef CLAIM_IRQ_AT_OPEN + free_irq (dev->irq, dev); +#endif + + ether1_reset (dev); + dev->start = 0; + dev->tbusy = 0; + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct enet_statistics *ether1_getstats (struct device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + return &priv->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 ether1_setmulticastlist (struct device *dev) +{ +} + +/* ------------------------------------------------------------------------- */ + +#ifdef MODULE + +static char ethernames[MAX_ECARDS][9]; +static struct device *my_ethers[MAX_ECARDS]; +static struct expansion_card *ec[MAX_ECARDS]; + +int init_module (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + { + my_ethers[i] = NULL; + ec[i] = NULL; + strcpy (ethernames[i], " "); + } + + i = 0; + + ecard_startfind(); + + do + { + if ((ec[i] = ecard_find(0, ether1_cids)) == NULL) + break; + + my_ethers[i] = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL); + memset (my_ethers[i], 0, sizeof (struct device)); + + my_ethers[i]->irq = ec[i]->irq; + my_ethers[i]->base_addr = ecard_address (ec[i], ECARD_IOC, ECARD_FAST); + my_ethers[i]->init = ether1_probe; + my_ethers[i]->name = ethernames[i]; + + ecard_claim (ec[i]); + + if (register_netdev (my_ethers[i]) != 0) + { + for (i = 0; i < 4; i++) + { + if (my_ethers[i]) + { + kfree (my_ethers[i]); + my_ethers[i] = NULL; + } + if (ec[i]) + { + ecard_release (ec[i]); + ec[i] = NULL; + } + } + return -EIO; + } + i++; + } + while (i < MAX_ECARDS); + + return i != 0 ? 0 : -ENODEV; +} + +void cleanup_module (void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) + { + if (my_ethers[i]) + { + unregister_netdev (my_ethers[i]); + release_region (my_ethers[i]->base_addr, 16); + release_region (my_ethers[i]->base_addr + 0x800, 4096); +#ifndef CLAIM_IRQ_AT_OPEN + free_irq (my_ethers[i]->irq, my_ethers[i]); +#endif + my_ethers[i] = NULL; + } + if (ec[i]) + { + ecard_release (ec[i]); + ec[i] = NULL; + } + } +} +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/acorn/net/ether1.h new/linux/drivers/acorn/net/ether1.h --- old/linux/drivers/acorn/net/ether1.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/net/ether1.h Tue Feb 17 00:49:47 1998 @@ -0,0 +1,281 @@ +/* + * linux/arch/arm/drivers/net/ether1.h + * + * network driver for Acorn Ether1 cards. + * + * (c) 1996 Russell King + */ + +#ifndef _LINUX_ether1_H +#define _LINUX_ether1_H + +#ifdef __ETHER1_C +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +/* Page register */ +#define REG_PAGE (dev->base_addr + 0x00) + +/* Control register */ +#define REG_CONTROL (dev->base_addr + 0x01) +#define CTRL_RST 0x01 +#define CTRL_LOOPBACK 0x02 +#define CTRL_CA 0x04 +#define CTRL_ACK 0x08 + +#define ETHER1_RAM (dev->base_addr + 0x800) + +/* HW address */ +#define IDPROM_ADDRESS (dev->base_addr + 0x09) + +struct ether1_priv { + struct enet_statistics stats; + unsigned int tx_link; + unsigned int tx_head; + volatile unsigned int tx_tail; + volatile unsigned int rx_head; + volatile unsigned int rx_tail; + unsigned char bus_type; + unsigned char resetting; + unsigned char initialising : 1; + unsigned char restart : 1; +}; + +static int ether1_open (struct device *dev); +static int ether1_sendpacket (struct sk_buff *skb, struct device *dev); +static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static int ether1_close (struct device *dev); +static struct enet_statistics *ether1_getstats (struct device *dev); +static void ether1_setmulticastlist (struct device *dev); + +#define I82586_NULL (-1) + +typedef struct { /* tdr */ + unsigned short tdr_status; + unsigned short tdr_command; + unsigned short tdr_link; + unsigned short tdr_result; +#define TDR_TIME (0x7ff) +#define TDR_SHORT (1 << 12) +#define TDR_OPEN (1 << 13) +#define TDR_XCVRPROB (1 << 14) +#define TDR_LNKOK (1 << 15) +} tdr_t; + +typedef struct { /* transmit */ + unsigned short tx_status; + unsigned short tx_command; + unsigned short tx_link; + unsigned short tx_tbdoffset; +} tx_t; + +typedef struct { /* tbd */ + unsigned short tbd_opts; +#define TBD_CNT (0x3fff) +#define TBD_EOL (1 << 15) + unsigned short tbd_link; + unsigned short tbd_bufl; + unsigned short tbd_bufh; +} tbd_t; + +typedef struct { /* rfd */ + unsigned short rfd_status; +#define RFD_NOEOF (1 << 6) +#define RFD_FRAMESHORT (1 << 7) +#define RFD_DMAOVRN (1 << 8) +#define RFD_NORESOURCES (1 << 9) +#define RFD_ALIGNERROR (1 << 10) +#define RFD_CRCERROR (1 << 11) +#define RFD_OK (1 << 13) +#define RFD_FDCONSUMED (1 << 14) +#define RFD_COMPLETE (1 << 15) + unsigned short rfd_command; +#define RFD_CMDSUSPEND (1 << 14) +#define RFD_CMDEL (1 << 15) + unsigned short rfd_link; + unsigned short rfd_rbdoffset; + unsigned char rfd_dest[6]; + unsigned char rfd_src[6]; + unsigned short rfd_len; +} rfd_t; + +typedef struct { /* rbd */ + unsigned short rbd_status; +#define RBD_ACNT (0x3fff) +#define RBD_ACNTVALID (1 << 14) +#define RBD_EOF (1 << 15) + unsigned short rbd_link; + unsigned short rbd_bufl; + unsigned short rbd_bufh; + unsigned short rbd_len; +} rbd_t; + +typedef struct { /* nop */ + unsigned short nop_status; + unsigned short nop_command; + unsigned short nop_link; +} nop_t; + +typedef struct { /* set multicast */ + unsigned short mc_status; + unsigned short mc_command; + unsigned short mc_link; + unsigned short mc_cnt; + unsigned char mc_addrs[1][6]; +} mc_t; + +typedef struct { /* set address */ + unsigned short sa_status; + unsigned short sa_command; + unsigned short sa_link; + unsigned char sa_addr[6]; +} sa_t; + +typedef struct { /* config command */ + unsigned short cfg_status; + unsigned short cfg_command; + unsigned short cfg_link; + unsigned char cfg_bytecnt; /* size foll data: 4 - 12 */ + unsigned char cfg_fifolim; /* FIFO threshold */ + unsigned char cfg_byte8; +#define CFG8_SRDY (1 << 6) +#define CFG8_SAVEBADF (1 << 7) + unsigned char cfg_byte9; +#define CFG9_ADDRLEN(x) (x) +#define CFG9_ADDRLENBUF (1 << 3) +#define CFG9_PREAMB2 (0 << 4) +#define CFG9_PREAMB4 (1 << 4) +#define CFG9_PREAMB8 (2 << 4) +#define CFG9_PREAMB16 (3 << 4) +#define CFG9_ILOOPBACK (1 << 6) +#define CFG9_ELOOPBACK (1 << 7) + unsigned char cfg_byte10; +#define CFG10_LINPRI(x) (x) +#define CFG10_ACR(x) (x << 4) +#define CFG10_BOFMET (1 << 7) + unsigned char cfg_ifs; + unsigned char cfg_slotl; + unsigned char cfg_byte13; +#define CFG13_SLOTH(x) (x) +#define CFG13_RETRY(x) (x << 4) + unsigned char cfg_byte14; +#define CFG14_PROMISC (1 << 0) +#define CFG14_DISBRD (1 << 1) +#define CFG14_MANCH (1 << 2) +#define CFG14_TNCRS (1 << 3) +#define CFG14_NOCRC (1 << 4) +#define CFG14_CRC16 (1 << 5) +#define CFG14_BTSTF (1 << 6) +#define CFG14_FLGPAD (1 << 7) + unsigned char cfg_byte15; +#define CFG15_CSTF(x) (x) +#define CFG15_ICSS (1 << 3) +#define CFG15_CDTF(x) (x << 4) +#define CFG15_ICDS (1 << 7) + unsigned short cfg_minfrmlen; +} cfg_t; + +typedef struct { /* scb */ + unsigned short scb_status; /* status of 82586 */ +#define SCB_STRXMASK (7 << 4) /* Receive unit status */ +#define SCB_STRXIDLE (0 << 4) /* Idle */ +#define SCB_STRXSUSP (1 << 4) /* Suspended */ +#define SCB_STRXNRES (2 << 4) /* No resources */ +#define SCB_STRXRDY (4 << 4) /* Ready */ +#define SCB_STCUMASK (7 << 8) /* Command unit status */ +#define SCB_STCUIDLE (0 << 8) /* Idle */ +#define SCB_STCUSUSP (1 << 8) /* Suspended */ +#define SCB_STCUACTV (2 << 8) /* Active */ +#define SCB_STRNR (1 << 12) /* Receive unit not ready */ +#define SCB_STCNA (1 << 13) /* Command unit not ready */ +#define SCB_STFR (1 << 14) /* Frame received */ +#define SCB_STCX (1 << 15) /* Command completed */ + unsigned short scb_command; /* Next command */ +#define SCB_CMDRXSTART (1 << 4) /* Start (at rfa_offset) */ +#define SCB_CMDRXRESUME (2 << 4) /* Resume reception */ +#define SCB_CMDRXSUSPEND (3 << 4) /* Suspend reception */ +#define SCB_CMDRXABORT (4 << 4) /* Abort reception */ +#define SCB_CMDCUCSTART (1 << 8) /* Start (at cbl_offset) */ +#define SCB_CMDCUCRESUME (2 << 8) /* Resume execution */ +#define SCB_CMDCUCSUSPEND (3 << 8) /* Suspend execution */ +#define SCB_CMDCUCABORT (4 << 8) /* Abort execution */ +#define SCB_CMDACKRNR (1 << 12) /* Ack RU not ready */ +#define SCB_CMDACKCNA (1 << 13) /* Ack CU not ready */ +#define SCB_CMDACKFR (1 << 14) /* Ack Frame received */ +#define SCB_CMDACKCX (1 << 15) /* Ack Command complete */ + unsigned short scb_cbl_offset; /* Offset of first command unit */ + unsigned short scb_rfa_offset; /* Offset of first receive frame area */ + unsigned short scb_crc_errors; /* Properly aligned frame with CRC error*/ + unsigned short scb_aln_errors; /* Misaligned frames */ + unsigned short scb_rsc_errors; /* Frames lost due to no space */ + unsigned short scb_ovn_errors; /* Frames lost due to slow bus */ +} scb_t; + +typedef struct { /* iscp */ + unsigned short iscp_busy; /* set by CPU before CA */ + unsigned short iscp_offset; /* offset of SCB */ + unsigned short iscp_basel; /* base of SCB */ + unsigned short iscp_baseh; +} iscp_t; + + /* this address must be 0xfff6 */ +typedef struct { /* scp */ + unsigned short scp_sysbus; /* bus size */ +#define SCP_SY_16BBUS 0x00 +#define SCP_SY_8BBUS 0x01 + unsigned short scp_junk[2]; /* junk */ + unsigned short scp_iscpl; /* lower 16 bits of iscp */ + unsigned short scp_iscph; /* upper 16 bits of iscp */ +} scp_t; + +/* commands */ +#define CMD_NOP 0 +#define CMD_SETADDRESS 1 +#define CMD_CONFIG 2 +#define CMD_SETMULTICAST 3 +#define CMD_TX 4 +#define CMD_TDR 5 +#define CMD_DUMP 6 +#define CMD_DIAGNOSE 7 + +#define CMD_MASK 7 + +#define CMD_INTR (1 << 13) +#define CMD_SUSP (1 << 14) +#define CMD_EOL (1 << 15) + +#define STAT_COLLISIONS (15) +#define STAT_COLLEXCESSIVE (1 << 5) +#define STAT_COLLAFTERTX (1 << 6) +#define STAT_TXDEFERRED (1 << 7) +#define STAT_TXSLOWDMA (1 << 8) +#define STAT_TXLOSTCTS (1 << 9) +#define STAT_NOCARRIER (1 << 10) +#define STAT_FAIL (1 << 11) +#define STAT_ABORTED (1 << 12) +#define STAT_OK (1 << 13) +#define STAT_BUSY (1 << 14) +#define STAT_COMPLETE (1 << 15) +#endif +#endif + +/* + * Ether1 card definitions: + * + * FAST accesses: + * +0 Page register + * 16 pages + * +4 Control + * '1' = reset + * '2' = loopback + * '4' = CA + * '8' = int ack + * + * RAM at address + 0x2000 + * Pod. Prod id = 3 + * Words after ID block [base + 8 words] + * +0 pcb issue (0x0c and 0xf3 invalid) + * +1 - +6 eth hw address + */ diff -ur --new-file old/linux/drivers/acorn/net/ether3.c new/linux/drivers/acorn/net/ether3.c --- old/linux/drivers/acorn/net/ether3.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/net/ether3.c Tue Feb 17 00:49:48 1998 @@ -0,0 +1,896 @@ +/* + * linux/drivers/net/ether3.c + * + * SEEQ nq8005 ethernet driver for Acorn/ANT Ether3 card + * for Acorn machines + * + * By Russell King, with some suggestions from borris@ant.co.uk + * + * Changelog: + * 1.04 RMK 29/02/1996 Won't pass packets that are from our ethernet + * address up to the higher levels - they're + * silently ignored. I/F can now be put into + * multicast mode. Receiver routine optimised. + * 1.05 RMK 30/02/1996 Now claims interrupt at open when part of + * the kernel rather than when a module. + * 1.06 RMK 02/03/1996 Various code cleanups + * 1.07 RMK 13/10/1996 Optimised interrupt routine and transmit + * routines. + * 1.08 RMK 14/10/1996 Fixed problem with too many packets, + * prevented the kernel message about dropped + * packets appearing too many times a second. + * Now does not disable all IRQs, only the IRQ + * used by this card. + * 1.09 RMK 10/11/1996 Only enables TX irq when buffer space is low, + * but we still service the TX queue if we get a + * RX interrupt. + * 1.10 RMK 15/07/1997 Fixed autoprobing of NQ8004. + * 1.11 RMK 16/11/1997 Fixed autoprobing of NQ8005A. + * 1.12 RMK 31/12/1997 Removed reference to dev_tint for Linux 2.1. + * + * TODO: + * When we detect a fatal error on the interface, we should restart it. + */ + +static char *version = "ether3 ethernet driver (c) 1995-1998 R.M.King v1.12\n"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ether3.h" + +#ifndef MODULE +#define CLAIM_IRQ_AT_OPEN +#endif + +static unsigned int net_debug = NET_DEBUG; + +static const card_ids ether3_cids[] = +{ + {MANU_ANT2, PROD_ANT_ETHER3}, + {MANU_ANT, PROD_ANT_ETHER3}, + {MANU_ANT, PROD_ANT_ETHERB}, /* trial - will etherb work? */ + {0xffff, 0xffff} +}; + +static void ether3_setmulticastlist(struct device *dev); +static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt); +static void ether3_tx(struct device *dev, struct dev_priv *priv); + +extern int inswb(int reg, void *buffer, int len); +extern int outswb(int reg, void *buffer, int len); + +#define struct dev_priv *priv = (struct dev_priv *)dev->priv \ + struct dev_priv *priv = (struct dev_priv *)dev->priv + +#define BUS_16 2 +#define BUS_8 1 +#define BUS_UNKNOWN 0 + +/* + * I'm not sure what address we should default to if the internal one + * is corrupted... + */ + +unsigned char def_eth_addr[6] = +{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; + +/* --------------------------------------------------------------------------- */ + +typedef enum { + buffer_write, + buffer_read +} buffer_rw_t; + +static int ether3_setbuffer(struct device *dev, buffer_rw_t read, int start) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + int timeout = 1000; + + outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); + outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND); + while ((inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) { + if (!timeout--) { + printk(KERN_ERR "%s: setbuffer broken\n", dev->name); + priv->broken = 1; + return 1; + } + udelay(1); + } + if (read == buffer_read) { + outw(start, REG_DMAADDR); + outw(priv->regs.command | CMD_FIFOREAD, REG_COMMAND); + } else { + outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND); + outw(start, REG_DMAADDR); + } + return 0; +} + +/* + * write data to the buffer memory + */ +#define ether3_writebuffer(dev,data,length) \ + outswb (REG_BUFWIN, (data), (length)) + +#define ether3_writeword(dev,data) \ + outw ((data), REG_BUFWIN) + +#define ether3_writelong(dev,data) { \ + unsigned long reg_bufwin = REG_BUFWIN; \ + outw ((data), reg_bufwin); \ + outw ((data) >> 16, reg_bufwin); \ +} + +/* + * read data from the buffer memory + */ +#define ether3_readbuffer(dev,data,length) \ + inswb (REG_BUFWIN, (data), (length)) + +#define ether3_readword(dev) \ + inw (REG_BUFWIN) + +#define ether3_readlong(dev) \ + inw (REG_BUFWIN) | (inw (REG_BUFWIN) << 16) + +/* + * Switch LED off... + */ +static void ether3_ledoff(unsigned long data) +{ + struct device *dev = (struct device *) data; + struct dev_priv *priv = (struct dev_priv *) dev->priv; + outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2); +} + +/* + * switch LED on... + */ +static inline void ether3_ledon(struct device *dev, struct dev_priv *priv) +{ + del_timer(&priv->timer); + priv->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */ + priv->timer.data = (unsigned long) dev; + priv->timer.function = ether3_ledoff; + add_timer(&priv->timer); + if (priv->regs.config2 & CFG2_CTRLO) + outw(priv->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2); +} + +/* + * Read the ethernet address string from the on board rom. + * This is an ascii string!!! + */ +static void ether3_addr(char *addr, struct expansion_card *ec) +{ + struct in_chunk_dir cd; + char *s; + + if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) { + int i; + for (i = 0; i < 6; i++) { + addr[i] = simple_strtoul(s + 1, &s, 0x10); + if (*s != (i == 5 ? ')' : ':')) + break; + } + if (i == 6) + return; + } + memcpy(addr, def_eth_addr, 6); +} + +/* --------------------------------------------------------------------------- */ + +static int ether3_ramtest(struct device *dev, unsigned char byte) +{ + unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL); + int i, ret = 0; + int max_errors = 4; + int bad = -1; + + if (!buffer) + return 1; + + memset(buffer, byte, RX_END); + ether3_setbuffer(dev, buffer_write, 0); + ether3_writebuffer(dev, buffer, TX_END); + ether3_setbuffer(dev, buffer_write, RX_START); + ether3_writebuffer(dev, buffer + RX_START, RX_LEN); + memset(buffer, byte ^ 0xff, RX_END); + ether3_setbuffer(dev, buffer_read, 0); + ether3_readbuffer(dev, buffer, TX_END); + ether3_setbuffer(dev, buffer_read, RX_START); + ether3_readbuffer(dev, buffer + RX_START, RX_LEN); + + for (i = 0; i < RX_END; i++) { + if (buffer[i] != byte) { + if (max_errors > 0 && bad != buffer[i]) { + printk("%s: RAM failed with (%02X instead of %02X) at 0x%04X", + dev->name, buffer[i], byte, i); + ret = 2; + max_errors--; + bad = i; + } + } else { + if (bad != -1) { + if (bad != i - 1) + printk(" - 0x%04X", i - 1); + printk("\n"); + bad = -1; + } + } + } + if (bad != -1) + printk(" - 0xffff\n"); + kfree(buffer); + + return ret; +} + +/* ------------------------------------------------------------------------------- */ + +static int ether3_init_2(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + int i; + + priv->regs.config1 = CFG1_RECVCOMPSTAT0 | CFG1_DMABURST8; + priv->regs.config2 = CFG2_CTRLO | CFG2_RECVCRC | CFG2_ERRENCRC; + priv->regs.command = 0; + /* + * Set up our hardware address + */ + outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], REG_BUFWIN); + + if (dev->flags & IFF_PROMISC) + priv->regs.config1 |= CFG1_RECVPROMISC; + else if (dev->flags & IFF_MULTICAST) + priv->regs.config1 |= CFG1_RECVSPECBRMULTI; + else + priv->regs.config1 |= CFG1_RECVSPECBROAD; + + /* + * There is a problem with the NQ8005 in that it occasionally losses the + * last two bytes. To get round this problem, we receive the CRC as well. + * That way, if we do loose the last two, then it doesn't matter + */ + outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); + outw((TX_END >> 8) - 1, REG_BUFWIN); + outw(priv->rx_head, REG_RECVPTR); + outw(0, REG_TRANSMITPTR); + outw(priv->rx_head >> 8, REG_RECVEND); + outw(priv->regs.config2, REG_CONFIG2); + outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); + outw(priv->regs.command, REG_COMMAND); + + i = ether3_ramtest(dev, 0x5A); + if (i) + return i; + i = ether3_ramtest(dev, 0x1E); + if (i) + return i; + + ether3_setbuffer(dev, buffer_write, 0); + ether3_writelong(dev, 0); + return 0; +} + +static void ether3_init_for_open(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + int i; + + memset(&priv->stats, 0, sizeof(struct enet_statistics)); + + priv->regs.command = 0; + outw(CMD_RXOFF | CMD_TXOFF, REG_COMMAND); + while (inw(REG_STATUS) & (STAT_RXON | STAT_TXON)); + + outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1); + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], REG_BUFWIN); + + priv->tx_used = 0; + priv->tx_head = 0; + priv->tx_tail = 0; + priv->regs.config2 |= CFG2_CTRLO; + priv->rx_head = RX_START; + + outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1); + outw((TX_END >> 8) - 1, REG_BUFWIN); + outw(priv->rx_head, REG_RECVPTR); + outw(priv->rx_head >> 8, REG_RECVEND); + outw(0, REG_TRANSMITPTR); + outw(priv->regs.config2, REG_CONFIG2); + outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); + + ether3_setbuffer(dev, buffer_write, 0); + ether3_writelong(dev, 0); + + priv->regs.command = CMD_ENINTRX; + outw(priv->regs.command | CMD_RXON, REG_COMMAND); +} + +/* + * This is the real probe routine. + */ +static int ether3_probe1(struct device *dev) +{ + static unsigned version_printed = 0; + struct dev_priv *priv; + unsigned int i, bus_type, error = ENODEV; + + if (net_debug && version_printed++ == 0) + printk(version); + + if (!dev->priv) { + dev->priv = kmalloc(sizeof(struct dev_priv), GFP_KERNEL); + if (!dev->priv) + return -ENOMEM; + } + priv = (struct dev_priv *) dev->priv; + memset(priv, 0, sizeof(struct dev_priv)); + + request_region(dev->base_addr, 128, "ether3"); + + /* Reset card... + */ + outb(0x80, REG_CONFIG2 + 1); + bus_type = BUS_UNKNOWN; + udelay(4); + + /* Test using Receive Pointer (16-bit register) to find out + * how the ether3 is connected to the bus... + */ + outb(0, REG_RECVPTR); + outb(1, REG_RECVPTR + 1); + + if (inb(REG_RECVPTR + 1) == 1) { + if (inb(REG_RECVPTR) == 0) + bus_type = BUS_8; + else if (inw(REG_RECVPTR) == 0x101) + bus_type = BUS_16; + } + switch (bus_type) { + case BUS_UNKNOWN: + printk(KERN_ERR "%s: unable to identify podule bus width\n", dev->name); + goto failed; + + case BUS_8: + printk(KERN_ERR "%s: ether3 found, but is an unsupported 8-bit card\n", dev->name); + goto failed; + + default: + break; + } + + printk("%s: ether3 found at %lx, IRQ%d, ether address ", dev->name, dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) + printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]); + + if (!ether3_init_2(dev)) { + dev->open = ether3_open; + dev->stop = ether3_close; + dev->hard_start_xmit = ether3_sendpacket; + dev->get_stats = ether3_getstats; + dev->set_multicast_list = ether3_setmulticastlist; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); +#ifndef CLAIM_IRQ_AT_OPEN + if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) + error = EAGAIN; + else +#endif + return 0; + } + failed: + kfree(dev->priv); + dev->priv = NULL; + release_region(dev->base_addr, 128); + return error; +} + +#ifndef MODULE +int ether3_probe(struct device *dev) +{ + struct expansion_card *ec; + + if (!dev) + return ENODEV; + + ecard_startfind(); + + if ((ec = ecard_find(0, ether3_cids)) == NULL) + return ENODEV; + + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); + dev->irq = ec->irq; + + ecard_claim(ec); + + ether3_addr(dev->dev_addr, ec); + return ether3_probe1(dev); +} +#endif + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ +static int ether3_open(struct device *dev) +{ + ether3_init_for_open(dev); + + MOD_INC_USE_COUNT; + +#ifdef CLAIM_IRQ_AT_OPEN + if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } +#endif + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + return 0; +} + +/* + * The inverse routine to ether3_open(). + */ +static int ether3_close(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + + dev->tbusy = 1; + dev->start = 0; + + disable_irq(dev->irq); + + outw(CMD_RXOFF | CMD_TXOFF, REG_COMMAND); + priv->regs.command = 0; + while (inw(REG_STATUS) & (STAT_RXON | STAT_TXON)); + outb(0x80, REG_CONFIG2 + 1); + outw(0, REG_COMMAND); + + enable_irq(dev->irq); +#ifdef CLAIM_IRQ_AT_OPEN + free_irq(dev->irq, dev); +#endif + + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Get the current statistics. This may be called with the card open or + * closed. + */ +static struct enet_statistics *ether3_getstats(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + return &priv->stats; +} + +/* + * Set or clear promiscuous/multicast mode filter for this adaptor. + * + * We don't attempt any packet filtering. The card may have a SEEQ 8004 + * in which does not have the other ethernet address registers present... + */ +static void ether3_setmulticastlist(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + + priv->regs.config1 &= ~CFG1_RECVPROMISC; + + if (dev->flags & IFF_PROMISC) { + /* promiscuous mode */ + priv->regs.config1 |= CFG1_RECVPROMISC; + } else if (dev->flags & IFF_ALLMULTI) { + priv->regs.config1 |= CFG1_RECVSPECBRMULTI; + } else + priv->regs.config1 |= CFG1_RECVSPECBROAD; + + outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); +} + +/* + * Transmit a packet + */ +static int ether3_sendpacket(struct sk_buff *skb, struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *) dev->priv; + retry: + if (!dev->tbusy) { + /* 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)) { + unsigned long flags; + unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned int ptr, nextptr; + + length = (length + 1) & ~1; + + if (priv->broken) { + dev_kfree_skb(skb, FREE_WRITE); + priv->stats.tx_dropped++; + dev->tbusy = 0; + return 0; + } + ptr = priv->tx_head; + nextptr = ptr + 0x600; + if (nextptr >= TX_END) + nextptr = 0; + if (nextptr == priv->tx_tail) + return 1; /* unable to queue */ + priv->tx_head = nextptr; + + save_flags_cli(flags); + ether3_setbuffer(dev, buffer_write, nextptr); + ether3_writelong(dev, 0); + ether3_setbuffer(dev, buffer_write, ptr + 4); + ether3_writebuffer(dev, skb->data, length); + ether3_writeword(dev, htons(nextptr)); + ether3_writeword(dev, (TXHDR_TRANSMIT | TXHDR_CHAINCONTINUE) >> 16); + ether3_setbuffer(dev, buffer_write, ptr); +#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) + ether3_writeword(dev, htons(ptr + length + 4)); + ether3_writeword(dev, (TXHDR_FLAGS >> 16)); + ether3_ledon(dev, priv); + priv->tx_used++; + if (priv->tx_used < MAX_TX_BUFFERED) + dev->tbusy = 0; + if (priv->tx_used >= (MAX_TX_BUFFERED * 3 / 4)) { + priv->regs.command |= CMD_ENINTTX; + outw(priv->regs.command, REG_COMMAND); + } + restore_flags(flags); + + dev->trans_start = jiffies; + dev_kfree_skb(skb, FREE_WRITE); + if (!(inw(REG_STATUS) & STAT_TXON)) { + outw(ptr, REG_TRANSMITPTR); + outw(priv->regs.command | CMD_TXON, REG_COMMAND); + } + return 0; + } else { + printk("%s: transmitter access conflict.\n", dev->name); + return 1; + } + } else { + /* 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; + del_timer(&priv->timer); + printk("%s: transmit timed out, network cable problem?\n", dev->name); + dev->tbusy = 0; + priv->regs.config2 |= CFG2_CTRLO; + outw(priv->regs.config2, REG_CONFIG2); + dev->trans_start = jiffies; + goto retry; + } +} + +static void ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *) dev_id; + struct dev_priv *priv; + unsigned int status; + +#if NET_DEBUG > 1 + if (net_debug & DEBUG_INT) + printk("eth3irq: %d ", irq); +#endif + + priv = (struct dev_priv *) dev->priv; + + dev->interrupt = 1; + status = inw(REG_STATUS); + /* + * Dispite we disable the TX interrupt when the packet buffer is + * mostly empty, if we happen to get a RX interrupt, we might as + * well handle the TX packets as well. + */ + if (status & STAT_INTTX) { /* Packets transmitted */ + outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND); + ether3_tx(dev, priv); + } + status = inw(REG_STATUS); + if (status & STAT_INTRX && ether3_rx(dev, priv, 12)) { /* Got packet(s). */ + /* + * We only acknowledge the interrupt if we have received all packets + * in the buffer or else we run out of memory. This is to allow the + * bh routines to run. + */ + outw(CMD_ACKINTRX | priv->regs.command, REG_COMMAND); + /* + * Receive again if some have become available - we may have cleared + * a pending IRQ + */ + ether3_rx(dev, priv, 4); + } + dev->interrupt = 0; + +#if NET_DEBUG > 1 + if (net_debug & DEBUG_INT) + printk("done\n"); +#endif +} + +/* + * If we have a good packet(s), get it/them out of the buffers. + */ +static int ether3_rx(struct device *dev, struct dev_priv *priv, unsigned int maxcnt) +{ + unsigned int next_ptr = priv->rx_head, received = 0; + ether3_ledon(dev, priv); + + do { + unsigned int this_ptr, status; + unsigned char addrs[16]; + + /* + * read the first 16 bytes from the buffer. + * This contains the status bytes etc and ethernet addresses, + * and we also check the source ethernet address to see if + * it originated from us. + */ + { + unsigned int temp_ptr; + ether3_setbuffer(dev, buffer_read, next_ptr); + temp_ptr = ether3_readword(dev); + status = ether3_readword(dev); + if (!(status & RXSTAT_DONE) || !temp_ptr) + break; + + this_ptr = next_ptr + 4; + next_ptr = ntohs(temp_ptr); + } + ether3_setbuffer(dev, buffer_read, this_ptr); + ether3_readbuffer(dev, addrs + 2, 12); + + /* + * ignore our own packets... + */ + if (!(*(unsigned long *) &dev->dev_addr[0] ^ *(unsigned long *) &addrs[2 + 6]) && + !(*(unsigned short *) &dev->dev_addr[4] ^ *(unsigned short *) &addrs[2 + 10])) { + maxcnt++; /* compensate for loopedback packet */ + outw(next_ptr >> 8, REG_RECVEND); + } else if (!(status & (RXSTAT_OVERSIZE | RXSTAT_CRCERROR | RXSTAT_DRIBBLEERROR | RXSTAT_SHORTPACKET))) { + unsigned int length = next_ptr - this_ptr; + struct sk_buff *skb; + + if (next_ptr <= this_ptr) + length += RX_END - RX_START; + + skb = dev_alloc_skb(length + 2); + if (skb) { + unsigned char *buf; + + skb->dev = dev; + skb_reserve(skb, 2); + buf = skb_put(skb, length); + ether3_readbuffer(dev, buf + 12, length - 12); + outw(next_ptr >> 8, REG_RECVEND); + *(unsigned short *) (buf + 0) = *(unsigned short *) (addrs + 2); + *(unsigned long *) (buf + 2) = *(unsigned long *) (addrs + 4); + *(unsigned long *) (buf + 6) = *(unsigned long *) (addrs + 8); + *(unsigned short *) (buf + 10) = *(unsigned short *) (addrs + 12); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + received++; + } else + goto dropping; + } else { + struct enet_statistics *stats = &priv->stats; + outw(next_ptr >> 8, REG_RECVEND); + if (status & RXSTAT_OVERSIZE) + stats->rx_length_errors++; + if (status & RXSTAT_CRCERROR) + stats->rx_crc_errors++; + if (status & RXSTAT_DRIBBLEERROR) + stats->rx_fifo_errors++; + if (status & RXSTAT_SHORTPACKET) + stats->rx_length_errors++; + stats->rx_errors++; + } + } + while (--maxcnt); + + done: + priv->stats.rx_packets += received; + priv->rx_head = next_ptr; + /* + * If rx went off line, then that means that the buffer may be full. We + * have dropped at least one packet. + */ + if (!(inw(REG_STATUS) & STAT_RXON)) { + priv->stats.rx_dropped++; + outw(next_ptr, REG_RECVPTR); + outw(priv->regs.command | CMD_RXON, REG_COMMAND); + } + return maxcnt; + + dropping:{ + static unsigned long last_warned; + + outw(next_ptr >> 8, REG_RECVEND); + /* + * Don't print this message too many times... + */ + if (jiffies - last_warned > 30 * HZ) { + last_warned = jiffies; + printk("%s: memory squeeze, dropping packet.\n", dev->name); + } + priv->stats.rx_dropped++; + goto done; + } +} + +/* + * Update stats for the transmitted packet(s) + */ +static void ether3_tx(struct device *dev, struct dev_priv *priv) +{ + unsigned int tx_tail = priv->tx_tail; + + do { + unsigned long status; + /* + * Read the packet header + */ + ether3_setbuffer(dev, buffer_read, tx_tail); + status = ether3_readlong(dev); + + /* + * Check to see if this packet has been transmitted + */ + if (!(status & TXSTAT_DONE) || !(status & TXHDR_TRANSMIT)) + break; + + /* + * Update errors + */ + if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS))) + priv->stats.tx_packets++; + else { + priv->stats.tx_errors++; + if (status & TXSTAT_16COLLISIONS) + priv->stats.collisions += 16; + if (status & TXSTAT_BABBLED) + priv->stats.tx_fifo_errors++; + } + + /* + * Get next packet address + */ + tx_tail += 0x600; + if (tx_tail >= TX_END) + tx_tail = 0; + + if (priv->tx_used) + priv->tx_used--; + } while (1); + + if (priv->tx_tail != tx_tail) { + priv->tx_tail = tx_tail; + if (priv->tx_used <= MAX_TX_BUFFERED) { + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } + } + priv->regs.command &= ~CMD_ENINTTX; + outw(priv->regs.command, REG_COMMAND); +} + +#ifdef MODULE + +char ethernames[MAX_ECARDS][9]; + +static struct device *my_ethers[MAX_ECARDS]; +static struct expansion_card *ec[MAX_ECARDS]; + +int init_module(void) +{ + int i; + + for (i = 0; i < MAX_ECARDS; i++) { + my_ethers[i] = NULL; + ec[i] = NULL; + strcpy(ethernames[i], " "); + } + + i = 0; + + ecard_startfind(); + + do { + if ((ec[i] = ecard_find(0, ether3_cids)) == NULL) + break; + + my_ethers[i] = (struct device *) kmalloc(sizeof(struct device), GFP_KERNEL); + memset(my_ethers[i], 0, sizeof(struct device)); + + my_ethers[i]->irq = ec[i]->irq; + my_ethers[i]->base_addr = ecard_address(ec[i], ECARD_MEMC, 0); + my_ethers[i]->init = ether3_probe1; + my_ethers[i]->name = ethernames[i]; + + ether3_addr(my_ethers[i]->dev_addr, ec[i]); + + ecard_claim(ec[i]); + + if (register_netdev(my_ethers[i]) != 0) { + for (i = 0; i < 4; i++) { + if (my_ethers[i]) { + kfree(my_ethers[i]); + my_ethers[i] = NULL; + } + if (ec[i]) { + ecard_release(ec[i]); + ec[i] = NULL; + } + } + return -EIO; + } + i++; + } + while (i < MAX_ECARDS); + + return i != 0 ? 0 : -ENODEV; +} + +void cleanup_module(void) +{ + if (MOD_IN_USE) { + printk("ether3: device busy, remove delayed\n"); + } else { + int i; + for (i = 0; i < MAX_ECARDS; i++) { + if (my_ethers[i]) { + release_region(my_ethers[i]->base_addr, 128); + unregister_netdev(my_ethers[i]); + my_ethers[i] = NULL; + } + if (ec[i]) { + ecard_release(ec[i]); + ec[i] = NULL; + } + } + } +} +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/acorn/net/ether3.h new/linux/drivers/acorn/net/ether3.h --- old/linux/drivers/acorn/net/ether3.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/net/ether3.h Tue Feb 17 00:49:48 1998 @@ -0,0 +1,169 @@ +/* + * linux/drivers/net/ether3.h + * + * network driver for Acorn/ANT Ether3 cards + */ + +#ifndef _LINUX_ether3_H +#define _LINUX_ether3_H + +/* use 0 for production, 1 for verification, >2 for debug. debug flags: */ +#define DEBUG_TX 2 +#define DEBUG_RX 4 +#define DEBUG_INT 8 +#define DEBUG_IC 16 +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +/* Command register definitions & bits */ +#define REG_COMMAND (dev->base_addr + 0x00) +#define CMD_ENINTDMA 0x0001 +#define CMD_ENINTRX 0x0002 +#define CMD_ENINTTX 0x0004 +#define CMD_ENINTBUFWIN 0x0008 +#define CMD_ACKINTDMA 0x0010 +#define CMD_ACKINTRX 0x0020 +#define CMD_ACKINTTX 0x0040 +#define CMD_ACKINTBUFWIN 0x0080 +#define CMD_DMAON 0x0100 +#define CMD_RXON 0x0200 +#define CMD_TXON 0x0400 +#define CMD_DMAOFF 0x0800 +#define CMD_RXOFF 0x1000 +#define CMD_TXOFF 0x2000 +#define CMD_FIFOREAD 0x4000 +#define CMD_FIFOWRITE 0x8000 + +/* status register */ +#define REG_STATUS (dev->base_addr + 0x00) +#define STAT_ENINTSTAT 0x0001 +#define STAT_ENINTRX 0x0002 +#define STAT_ENINTTX 0x0004 +#define STAT_ENINTBUFWIN 0x0008 +#define STAT_INTDMA 0x0010 +#define STAT_INTRX 0x0020 +#define STAT_INTTX 0x0040 +#define STAT_INTBUFWIN 0x0080 +#define STAT_DMAON 0x0100 +#define STAT_RXON 0x0200 +#define STAT_TXON 0x0400 +#define STAT_FIFOFULL 0x2000 +#define STAT_FIFOEMPTY 0x4000 +#define STAT_FIFODIR 0x8000 + +/* configuration register 1 */ +#define REG_CONFIG1 (dev->base_addr + 0x10) +#define CFG1_BUFSELSTAT0 0x0000 +#define CFG1_BUFSELSTAT1 0x0001 +#define CFG1_BUFSELSTAT2 0x0002 +#define CFG1_BUFSELSTAT3 0x0003 +#define CFG1_BUFSELSTAT4 0x0004 +#define CFG1_BUFSELSTAT5 0x0005 +#define CFG1_ADDRPROM 0x0006 +#define CFG1_TRANSEND 0x0007 +#define CFG1_LOCBUFMEM 0x0008 +#define CFG1_INTVECTOR 0x0009 +#define CFG1_DMABURSTCONT 0x0000 +#define CFG1_DMABURST800NS 0x0010 +#define CFG1_DMABURST1600NS 0x0020 +#define CFG1_DMABURST3200NS 0x0030 +#define CFG1_DMABURST1 0x0000 +#define CFG1_DMABURST4 0x0040 +#define CFG1_DMABURST8 0x0080 +#define CFG1_DMABURST16 0x00C0 +#define CFG1_RECVCOMPSTAT0 0x0100 +#define CFG1_RECVCOMPSTAT1 0x0200 +#define CFG1_RECVCOMPSTAT2 0x0400 +#define CFG1_RECVCOMPSTAT3 0x0800 +#define CFG1_RECVCOMPSTAT4 0x1000 +#define CFG1_RECVCOMPSTAT5 0x2000 +#define CFG1_RECVSPECONLY 0x0000 +#define CFG1_RECVSPECBROAD 0x4000 +#define CFG1_RECVSPECBRMULTI 0x8000 +#define CFG1_RECVPROMISC 0xC000 + +/* configuration register 2 */ +#define REG_CONFIG2 (dev->base_addr + 0x20) +#define CFG2_BYTESWAP 0x0001 +#define CFG2_ERRENCRC 0x0008 +#define CFG2_ERRENDRIBBLE 0x0010 +#define CFG2_ERRSHORTFRAME 0x0020 +#define CFG2_SLOTSELECT 0x0040 +#define CFG2_PREAMSELECT 0x0080 +#define CFG2_ADDRLENGTH 0x0100 +#define CFG2_RECVCRC 0x0200 +#define CFG2_XMITNOCRC 0x0400 +#define CFG2_LOOPBACK 0x0800 +#define CFG2_CTRLO 0x1000 +#define CFG2_RESET 0x8000 + +#define REG_RECVEND (dev->base_addr + 0x30) + +#define REG_BUFWIN (dev->base_addr + 0x40) + +#define REG_RECVPTR (dev->base_addr + 0x50) + +#define REG_TRANSMITPTR (dev->base_addr + 0x60) + +#define REG_DMAADDR (dev->base_addr + 0x70) + +/* + * Cards transmit/receive headers + */ +#define TX_NEXT (0xffff) +#define TXHDR_ENBABBLEINT (1 << 16) +#define TXHDR_ENCOLLISIONINT (1 << 17) +#define TXHDR_EN16COLLISION (1 << 18) +#define TXHDR_ENSUCCESS (1 << 19) +#define TXHDR_DATAFOLLOWS (1 << 21) +#define TXHDR_CHAINCONTINUE (1 << 22) +#define TXHDR_TRANSMIT (1 << 23) +#define TXSTAT_BABBLED (1 << 24) +#define TXSTAT_COLLISION (1 << 25) +#define TXSTAT_16COLLISIONS (1 << 26) +#define TXSTAT_DONE (1 << 31) + +#define RX_NEXT (0xffff) +#define RXHDR_CHAINCONTINUE (1 << 6) +#define RXHDR_RECEIVE (1 << 7) +#define RXSTAT_OVERSIZE (1 << 8) +#define RXSTAT_CRCERROR (1 << 9) +#define RXSTAT_DRIBBLEERROR (1 << 10) +#define RXSTAT_SHORTPACKET (1 << 11) +#define RXSTAT_DONE (1 << 15) + + +#define TX_END 0x6000 +#define RX_START 0x6000 +#define RX_LEN 0xA000 +#define RX_END 0x10000 +/* must be a power of 2 and greater than MAX_TX_BUFFERED */ +#define MAX_TXED 16 +#define MAX_TX_BUFFERED 10 + +struct dev_priv { + struct { + unsigned int command; + unsigned int config1; + unsigned int config2; + } regs; + unsigned int tx_head; /* address to insert next packet */ + unsigned int tx_tail; /* address of transmitting packet */ + unsigned int tx_used; /* number of 'slots' used */ + unsigned int rx_head; /* address to fetch next packet from */ + struct enet_statistics stats; + struct timer_list timer; + int broken; /* 0 = ok, 1 = something went wrong */ +}; + +extern int ether3_probe (struct device *dev); +static int ether3_probe1 (struct device *dev); +static int ether3_open (struct device *dev); +static int ether3_sendpacket (struct sk_buff *skb, struct device *dev); +static void ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static int ether3_close (struct device *dev); +static struct enet_statistics *ether3_getstats (struct device *dev); +static void ether3_setmulticastlist (struct device *dev); + +#endif diff -ur --new-file old/linux/drivers/acorn/net/etherh.c new/linux/drivers/acorn/net/etherh.c --- old/linux/drivers/acorn/net/etherh.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/net/etherh.c Tue Feb 17 00:49:48 1998 @@ -0,0 +1,538 @@ +/* + * linux/drivers/net/etherh.c + * + * NS8390 ANT etherh specific driver + * For Acorn machines + * + * By Russell King. + * + * Changelog: + * 08-Dec-1996 RMK 1.00 Created + * RMK 1.03 Added support for EtherLan500 cards + * 23-Nov-1997 RMK 1.04 Added media autodetection + * + * Insmod Module Parameters + * ------------------------ + * io= + * irq= + * xcvr=<0|1> 0 = 10bT, 1=10b2 (Lan600/600A only) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "8390.h" + +#define NET_DEBUG 0 +#define DEBUG_INIT 2 + +static unsigned int net_debug = NET_DEBUG; +static const card_ids etherh_cids[] = { + { MANU_I3, PROD_I3_ETHERLAN500 }, + { MANU_I3, PROD_I3_ETHERLAN600 }, + { MANU_I3, PROD_I3_ETHERLAN600A }, + { 0xffff, 0xffff } +}; + +static char *version = "etherh [500/600/600A] ethernet driver (c) 1997 R.M.King v1.04\n"; + +#define ETHERH500_DATAPORT 0x200 /* MEMC */ +#define ETHERH500_NS8390 0x000 /* MEMC */ +#define ETHERH500_CTRLPORT 0x200 /* IOC */ + +#define ETHERH600_DATAPORT 16 /* MEMC */ +#define ETHERH600_NS8390 0x200 /* MEMC */ +#define ETHERH600_CTRLPORT 0x080 /* MEMC */ + +#define ETHERH_CP_IE 1 +#define ETHERH_CP_IF 2 + +#define ETHERH_TX_START_PAGE 1 +#define ETHERH_STOP_PAGE 0x7f + +/* --------------------------------------------------------------------------- */ + +/* + * Read the ethernet address string from the on board rom. + * This is an ascii string... + */ +static int +etherh_addr (char *addr, struct expansion_card *ec) +{ + struct in_chunk_dir cd; + char *s; + + if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) { + int i; + for (i = 0; i < 6; i++) { + addr[i] = simple_strtoul(s + 1, &s, 0x10); + if (*s != (i == 5? ')' : ':')) + break; + } + if (i == 6) + return 0; + } + return ENODEV; +} + +/* + * Reset the 8390 (hard reset) + */ +static void +etherh_reset (struct device *dev) +{ + unsigned int addr = dev->base_addr; + int crb; + + if (dev->mem_end == PROD_I3_ETHERLAN600 || dev->mem_end == PROD_I3_ETHERLAN600A) { + crb = inb (addr + EN0_RCNTHI) & 0xf8; + outb (ei_status.interface_num ? crb | 1: crb, addr+EN0_RCNTHI); + } +} + +/* + * Write a block of data out to the 8390 + */ +static void +etherh_block_output (struct device *dev, int count, const unsigned char *buf, int start_page) +{ + unsigned int addr, dma_addr; + unsigned long dma_start; + + if (ei_status.dmaing) { + printk ("%s: DMAing conflict in etherh_block_input: " + " DMAstat %d irqlock %d intr %d\n", dev->name, + ei_status.dmaing, ei_status.irqlock, dev->interrupt); + return; + } + + ei_status.dmaing |= 1; + + addr = dev->base_addr; + dma_addr = dev->mem_start; + + count = (count + 1) & ~1; + outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); + + outb (0x42, addr + EN0_RCNTLO); + outb (0x00, addr + EN0_RCNTHI); + outb (0x42, addr + EN0_RSARLO); + outb (0x00, addr + EN0_RSARHI); + outb (E8390_RREAD | E8390_START, addr + E8390_CMD); + + udelay (1); + + outb (ENISR_RDC, addr + EN0_ISR); + outb (count, addr + EN0_RCNTLO); + outb (count >> 8, addr + EN0_RCNTHI); + outb (0, addr + EN0_RSARLO); + outb (start_page, addr + EN0_RSARHI); + outb (E8390_RWRITE | E8390_START, addr + E8390_CMD); + + if (ei_status.word16) + outsw (dma_addr, buf, count >> 1); +#ifdef BIT8 + else + outsb (dma_addr, buf, count); +#endif + + dma_start = jiffies; + + while ((inb (addr + EN0_ISR) & ENISR_RDC) == 0) + if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + printk ("%s: timeout waiting for TX RDC\n", dev->name); + etherh_reset (dev); + NS8390_init (dev, 1); + break; + } + + outb (ENISR_RDC, addr + EN0_ISR); + ei_status.dmaing &= ~1; +} + +/* + * Read a block of data from the 8390 + */ +static void +etherh_block_input (struct device *dev, int count, struct sk_buff *skb, int ring_offset) +{ + unsigned int addr, dma_addr; + unsigned char *buf; + + if (ei_status.dmaing) { + printk ("%s: DMAing conflict in etherh_block_input: " + " DMAstat %d irqlock %d intr %d\n", dev->name, + ei_status.dmaing, ei_status.irqlock, dev->interrupt); + return; + } + + ei_status.dmaing |= 1; + + addr = dev->base_addr; + dma_addr = dev->mem_start; + + buf = skb->data; + outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); + outb (count, addr + EN0_RCNTLO); + outb (count >> 8, addr + EN0_RCNTHI); + outb (ring_offset, addr + EN0_RSARLO); + outb (ring_offset >> 8, addr + EN0_RSARHI); + outb (E8390_RREAD | E8390_START, addr + E8390_CMD); + + if (ei_status.word16) { + insw (dma_addr, buf, count >> 1); + if (count & 1) + buf[count - 1] = inb (dma_addr); + } +#ifdef BIT8 + else + insb (dma_addr, buf, count); +#endif + + outb (ENISR_RDC, addr + EN0_ISR); + ei_status.dmaing &= ~1; +} + +/* + * Read a header from the 8390 + */ +static void +etherh_get_header (struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned int addr, dma_addr; + + if (ei_status.dmaing) { + printk ("%s: DMAing conflict in etherh_get_header: " + " DMAstat %d irqlock %d intr %d\n", dev->name, + ei_status.dmaing, ei_status.irqlock, dev->interrupt); + return; + } + + ei_status.dmaing |= 1; + + addr = dev->base_addr; + dma_addr = dev->mem_start; + + outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD); + outb (sizeof (*hdr), addr + EN0_RCNTLO); + outb (0, addr + EN0_RCNTHI); + outb (0, addr + EN0_RSARLO); + outb (ring_page, addr + EN0_RSARHI); + outb (E8390_RREAD | E8390_START, addr + E8390_CMD); + + if (ei_status.word16) + insw (dma_addr, hdr, sizeof (*hdr) >> 1); +#ifdef BIT8 + else + insb (dma_addr, hdr, sizeof (*hdr)); +#endif + + outb (ENISR_RDC, addr + EN0_ISR); + ei_status.dmaing &= ~1; +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ +static int +etherh_open(struct device *dev) +{ + unsigned int addr = dev->base_addr; + int crb; + + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, ei_interrupt, 0, "etherh", dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + if (dev->mem_end == PROD_I3_ETHERLAN600 || dev->mem_end == PROD_I3_ETHERLAN600A) { + crb = inb (addr + EN0_RCNTHI) & 0xf8; + outb (ei_status.interface_num ? crb | 1: crb, addr+EN0_RCNTHI); + } + + ei_open (dev); + return 0; +} + +/* + * The inverse routine to etherh_open(). + */ +static int +etherh_close(struct device *dev) +{ + ei_close (dev); + free_irq (dev->irq, dev); + + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * This is the real probe routine. + */ +static int +etherh_probe1(struct device *dev) +{ + static int version_printed; + unsigned int addr, i, reg0, tmp; + char *dev_type; + + addr = dev->base_addr; + + if (net_debug && version_printed++ == 0) + printk(version); + + switch (dev->mem_end) { + case PROD_I3_ETHERLAN500: + dev_type = "500 "; + break; + case PROD_I3_ETHERLAN600: + dev_type = "600 "; + break; + case PROD_I3_ETHERLAN600A: + dev_type = "600A "; + break; + default: + dev_type = ""; + } + + reg0 = inb (addr); + if (reg0 == 0xff) { + if (net_debug & DEBUG_INIT) + printk ("%s: etherh error: NS8390 command register wrong\n", dev->name); + return -ENODEV; + } + + outb (E8390_NODMA | E8390_PAGE1 | E8390_STOP, addr + E8390_CMD); + tmp = inb (addr + 13); + outb (0xff, addr + 13); + outb (E8390_NODMA | E8390_PAGE0, addr + E8390_CMD); + inb (addr + EN0_COUNTER0); + if (inb (addr + EN0_COUNTER0) != 0) { + if (net_debug & DEBUG_INIT) + printk ("%s: etherh error: NS8390 not found\n", dev->name); + outb (reg0, addr); + outb (tmp, addr + 13); + return -ENODEV; + } + + if (ethdev_init (dev)) + return -ENOMEM; + + request_region (addr, 16, "etherh"); + + printk("%s: etherh %sfound at %lx, IRQ%d, ether address ", + dev->name, dev_type, dev->base_addr, dev->irq); + + for (i = 0; i < 6; i++) + printk (i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]); + + ei_status.name = "etherh"; + ei_status.word16 = 1; + ei_status.interface_num = dev->if_port & 1; + ei_status.tx_start_page = ETHERH_TX_START_PAGE; + ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES; + ei_status.stop_page = ETHERH_STOP_PAGE; + ei_status.reset_8390 = etherh_reset; + ei_status.block_input = etherh_block_input; + ei_status.block_output = etherh_block_output; + ei_status.get_8390_hdr = etherh_get_header; + dev->open = etherh_open; + dev->stop = etherh_close; + + NS8390_init (dev, 0); + return 0; +} + +static void etherh_irq_enable (ecard_t *ec, int irqnr) +{ + unsigned int ctrl_addr = (unsigned int)ec->irq_data; + outb (inb (ctrl_addr) | ETHERH_CP_IE, ctrl_addr); +} + +static void etherh_irq_disable (ecard_t *ec, int irqnr) +{ + unsigned int ctrl_addr = (unsigned int)ec->irq_data; + outb (inb (ctrl_addr) & ~ETHERH_CP_IE, ctrl_addr); +} + +static expansioncard_ops_t etherh_ops = { + etherh_irq_enable, + etherh_irq_disable, + NULL, + NULL +}; + +static void etherh_initdev (ecard_t *ec, struct device *dev) +{ + ecard_claim (ec); + + dev->irq = ec->irq; + dev->mem_end = ec->cld.product; + + switch (ec->cld.product) { + case PROD_I3_ETHERLAN500: + dev->base_addr = ecard_address (ec, ECARD_MEMC, 0) + ETHERH500_NS8390; + dev->mem_start = dev->base_addr + ETHERH500_DATAPORT; + ec->irq_data = (void *)ecard_address (ec, ECARD_IOC, ECARD_FAST) + + ETHERH500_CTRLPORT; + break; + + case PROD_I3_ETHERLAN600: + case PROD_I3_ETHERLAN600A: + dev->base_addr = ecard_address (ec, ECARD_MEMC, 0) + ETHERH600_NS8390; + dev->mem_start = dev->base_addr + ETHERH600_DATAPORT; + ec->irq_data = (void *)(dev->base_addr + ETHERH600_CTRLPORT); + break; + + default: + printk ("%s: etherh error: unknown card type\n", dev->name); + } + ec->ops = ðerh_ops; + + etherh_addr (dev->dev_addr, ec); +} + +#ifndef MODULE +int +etherh_probe(struct device *dev) +{ + if (!dev) + return ENODEV; + + ecard_startfind (); + + if (!dev->base_addr) { + struct expansion_card *ec; + + if ((ec = ecard_find (0, etherh_cids)) == NULL) + return ENODEV; + + etherh_initdev (ec, dev); + } + return etherh_probe1 (dev); +} +#endif + +#ifdef MODULE +#define MAX_ETHERH_CARDS 2 + +static int io[MAX_ETHERH_CARDS]; +static int irq[MAX_ETHERH_CARDS]; +static int xcvr[MAX_ETHERH_CARDS] = { 1, 1 }; +static char ethernames[MAX_ETHERH_CARDS][9]; +static struct device *my_ethers[MAX_ETHERH_CARDS]; +static struct expansion_card *ec[MAX_ETHERH_CARDS]; + +int +init_module(void) +{ + struct device *dev = NULL; + struct expansion_card *boguscards[MAX_ETHERH_CARDS]; + int i, found = 0; + + for (i = 0; i < MAX_ETHERH_CARDS; i++) { + my_ethers[i] = NULL; + boguscards[i] = NULL; + ec[i] = NULL; + strcpy (ethernames[i], " "); + } + + ecard_startfind(); + + for (i = 0; i < MAX_ETHERH_CARDS; i++) { + if (!dev) + dev = (struct device *)kmalloc (sizeof (struct device), GFP_KERNEL); + if (dev) + memset (dev, 0, sizeof (struct device)); + + if (!io[i]) { + if ((ec[i] = ecard_find (0, etherh_cids)) == NULL) + continue; + if (!dev) + return -ENOMEM; + + etherh_initdev (ec[i], dev); + } else { + ec[i] = NULL; + if (!dev) + return -ENOMEM; + dev->base_addr = io[i]; + dev->irq = irq[i]; + } + + dev->init = etherh_probe1; + dev->name = ethernames[i]; + dev->if_port = xcvr[i]; + + my_ethers[i] = dev; + + if (register_netdev (my_ethers[i]) != 0) { + printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr); + if (ec[i]) { + boguscards[i] = ec[i]; + ec[i] = NULL; + } + continue; + } + found ++; + dev = NULL; + } + if (dev) + kfree (dev); + for (i = 0; i < MAX_ETHERH_CARDS; i++) + if (boguscards[i]) { + boguscards[i]->ops = NULL; + ecard_release (boguscards[i]); + } + if (!found) + return -ENODEV; + return 0; +} + +void +cleanup_module(void) +{ + int i; + for (i = 0; i < MAX_ETHERH_CARDS; i++) { + if (my_ethers[i]) { + unregister_netdev(my_ethers[i]); + release_region (my_ethers[i]->base_addr, 16); + kfree (my_ethers[i]); + my_ethers[i] = NULL; + } + if (ec[i]) { + ec[i]->ops = NULL; + ecard_release(ec[i]); + ec[i] = NULL; + } + } +} +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/acorn/net/net-probe.c new/linux/drivers/acorn/net/net-probe.c --- old/linux/drivers/acorn/net/net-probe.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/net/net-probe.c Tue Feb 17 00:49:48 1998 @@ -0,0 +1,31 @@ +/* + * Acorn specific net device driver probe routine + * + * Copyright (C) 1998 Russell King + */ +#include +#include +#include +#include + +extern int ether1_probe (struct device *dev); +extern int ether3_probe (struct device *dev); +extern int etherh_probe (struct device *dev); + +__initfunc(int acorn_ethif_probe(struct device *dev)) +{ + if (1 +#ifdef CONFIG_ARM_ETHERH + && etherh_probe (dev) +#endif +#ifdef CONFIG_ARM_ETHER3 + && ether3_probe (dev) +#endif +#ifdef CONFIG_ARM_ETHER1 + && ether1_probe (dev) +#endif + && 1) { + return 1; + } + return 0; +} diff -ur --new-file old/linux/drivers/acorn/scsi/Config.in new/linux/drivers/acorn/scsi/Config.in --- old/linux/drivers/acorn/scsi/Config.in Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/Config.in Tue Feb 3 21:57:43 1998 @@ -0,0 +1,21 @@ +# +# SCSI driver configuration for Acorn +# +dep_tristate 'Acorn SCSI card (aka30) support' CONFIG_SCSI_ACORNSCSI_3 $CONFIG_SCSI +if [ "$CONFIG_SCSI_ACORNSCSI_3" != "n" ]; then + bool ' Support SCSI 2 Tagged queueing' CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + bool ' Support SCSI 2 Synchronous Transfers' CONFIG_SCSI_ACORNSCSI_SYNC +fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'CumanaSCSI II support (Experimental)' CONFIG_SCSI_CUMANA_2 $CONFIG_SCSI + dep_tristate 'PowerTec support (Experimental)' CONFIG_SCSI_POWERTECSCSI $CONFIG_SCSI + + comment 'The following drives are not fully supported' + + dep_tristate 'CumanaSCSI I support' CONFIG_SCSI_CUMANA_1 $CONFIG_SCSI + if [ "$CONFIG_ARCH_ARC" = "y" -o "$CONFIG_ARCH_A5K" = "y" ]; then + dep_tristate 'EcoScsi support' CONFIG_SCSI_ECOSCSI $CONFIG_SCSI + fi + dep_tristate 'Oak SCSI support' CONFIG_SCSI_OAK1 $CONFIG_SCSI +fi + diff -ur --new-file old/linux/drivers/acorn/scsi/Makefile new/linux/drivers/acorn/scsi/Makefile --- old/linux/drivers/acorn/scsi/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/Makefile Sat Feb 7 16:18:17 1998 @@ -0,0 +1,103 @@ +# +# Makefile for drivers/acorn/scsi +# + +L_TARGET := acorn-scsi.a +L_OBJS := +LX_OBJS := +M_OBJS := +MX_OBJS := +MOD_LIST_NAME := ACORN_SCSI_MODULES + +CONFIG_QUEUE_BUILTIN := +CONFIG_FAS216_BUILTIN := +CONFIG_QUEUE_MODULE := +CONFIG_FAS216_MODULE := + +ifeq ($(CONFIG_SCSI_ACORNSCSI_3),y) + L_OBJS += acornscsi.o acornscsi-io.o + CONFIG_QUEUE_BUILTIN=y +else + ifeq ($(CONFIG_SCSI_ACORNSCSI_3),m) + M_OBJS += acornscsi_mod.o + CONFIG_QUEUE_MODULE=y + endif +endif + +ifeq ($(CONFIG_SCSI_CUMANA_1),y) + L_OBJS += cumana_1.o +else + ifeq ($(CONFIG_SCSI_CUMANA_1),m) + M_OBJS += cumana_1.o + endif +endif + +ifeq ($(CONFIG_SCSI_CUMANA_2),y) + L_OBJS += cumana_2.o + CONFIG_QUEUE_BUILTIN=y + CONFIG_FAS216_BUILTIN=y +else + ifeq ($(CONFIG_SCSI_CUMANA_2),m) + M_OBJS += cumana_2.o + CONFIG_QUEUE_MODULE=y + CONFIG_FAS216_MODULE=y + endif +endif + +ifeq ($(CONFIG_SCSI_ECOSCSI),y) + L_OBJS += ecoscsi.o +else + ifeq ($(CONFIG_SCSI_ECOSCSI),m) + M_OBJS += ecoscsi.o + endif +endif + +ifeq ($(CONFIG_SCSI_OAK1),y) + L_OBJS += oak.o +else + ifeq ($(CONFIG_SCSI_OAK1),m) + M_OBJS += oak.o + endif +endif + +ifeq ($(CONFIG_SCSI_POWERTECSCSI),y) + L_OBJS += powertec.o + CONFIG_QUEUE_BUILTIN=y + CONFIG_FAS216_BUILTIN=y +else + ifeq ($(CONFIG_SCSI_POWERTECSCSI),m) + M_OBJS += powertec.o + CONFIG_QUEUE_MODULE=y + CONFIG_FAS216_MODULE=y + endif +endif + +ifeq ($(CONFIG_QUEUE_BUILTIN),y) + LX_OBJS += queue.o msgqueue.o +else + ifeq ($(CONFIG_QUEUE_MODULE),y) + MX_OBJS += queue.o msgqueue.o + endif +endif + +ifeq ($(CONFIG_FAS216_BUILTIN),y) + LX_OBJS += fas216.o +else + ifeq ($(CONFIG_FAS216_MODULE),y) + MX_OBJS += fas216.o + endif +endif + +include $(TOPDIR)/Rules.make + +acornscsi_mod.o: acornscsi.o acornscsi-io.o + $(LD) $(LD_RFLAG) -r -o $@ acornscsi.o acornscsi-io.o + +%.o: %.S +ifndef $(CONFIG_BINUTILS_NEW) + $(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 diff -ur --new-file old/linux/drivers/acorn/scsi/acornscsi-io.S new/linux/drivers/acorn/scsi/acornscsi-io.S --- old/linux/drivers/acorn/scsi/acornscsi-io.S Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/acornscsi-io.S Mon Jan 12 01:45:53 1998 @@ -0,0 +1,139 @@ +@ linux/arch/arm/drivers/scsi/acornscsi-io.S: Acorn SCSI card IO +#include + +#include +#include + +#if (IO_BASE == (PCIO_BASE & 0xff000000)) +#define ADDR(off,reg) \ + tst off, $0x80000000 ;\ + mov reg, $IO_BASE ;\ + orreq reg, reg, $(PCIO_BASE & 0x00ff0000) +#else +#define ADDR(off,reg) \ + tst off, $0x80000000 ;\ + movne reg, $IO_BASE ;\ + moveq reg, $(PCIO_BASE & 0xff000000) ;\ + orreq reg, reg, $(PCIO_BASE & 0x00ff0000) +#endif + +@ Purpose: transfer a block of data from the acorn scsi card to memory +@ Proto : void acornscsi_in(unsigned int addr_start, char *buffer, int length) +@ Returns: nothing + + .align +ENTRY(__acornscsi_in) + stmfd sp!, {r4 - r7, lr} + bic r0, r0, #3 + mov lr, #0xff + orr lr, lr, #0xff00 +acornscsi_in16lp: + subs r2, r2, #16 + bmi acornscsi_in8 + ldmia r0!, {r3, r4, r5, r6} + and r3, r3, lr + orr r3, r3, r4, lsl #16 + and r4, r5, lr + orr r4, r4, r6, lsl #16 + ldmia r0!, {r5, r6, r7, ip} + and r5, r5, lr + orr r5, r5, r6, lsl #16 + and r6, r7, lr + orr r6, r6, ip, lsl #16 + stmia r1!, {r3 - r6} + bne acornscsi_in16lp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +acornscsi_in8: adds r2, r2, #8 + bmi acornscsi_in4 + ldmia r0!, {r3, r4, r5, r6} + and r3, r3, lr + orr r3, r3, r4, lsl #16 + and r4, r5, lr + orr r4, r4, r6, lsl #16 + stmia r1!, {r3 - r4} + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r2, r2, #8 + +acornscsi_in4: adds r2, r2, #4 + bmi acornscsi_in2 + ldmia r0!, {r3, r4} + and r3, r3, lr + orr r3, r3, r4, lsl #16 + str r3, [r1], #4 + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r2, r2, #4 + +acornscsi_in2: adds r2, r2, #2 + ldr r3, [r0], #4 + and r3, r3, lr + strb r3, [r1], #1 + mov r3, r3, lsr #8 + strplb r3, [r1], #1 + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ Purpose: transfer a block of data from memory to the acorn scsi card +@ Proto : void acornscsi_in(unsigned int addr_start, char *buffer, int length) +@ Returns: nothing + +ENTRY(__acornscsi_out) + stmfd sp!, {r4 - r6, lr} + bic r0, r0, #3 +acornscsi_out16lp: + subs r2, r2, #16 + bmi acornscsi_out8 + ldmia r1!, {r4, r6, ip, lr} + mov r3, r4, lsl #16 + orr r3, r3, r3, lsr #16 + mov r4, r4, lsr #16 + orr r4, r4, r4, lsl #16 + mov r5, r6, lsl #16 + orr r5, r5, r5, lsr #16 + mov r6, r6, lsr #16 + orr r6, r6, r6, lsl #16 + stmia r0!, {r3, r4, r5, r6} + mov r3, ip, lsl #16 + orr r3, r3, r3, lsr #16 + mov r4, ip, lsr #16 + orr r4, r4, r4, lsl #16 + mov ip, lr, lsl #16 + orr ip, ip, ip, lsr #16 + mov lr, lr, lsr #16 + orr lr, lr, lr, lsl #16 + stmia r0!, {r3, r4, ip, lr} + bne acornscsi_out16lp + LOADREGS(fd, sp!, {r4 - r6, pc}) + +acornscsi_out8: adds r2, r2, #8 + bmi acornscsi_out4 + ldmia r1!, {r4, r6} + mov r3, r4, lsl #16 + orr r3, r3, r3, lsr #16 + mov r4, r4, lsr #16 + orr r4, r4, r4, lsl #16 + mov r5, r6, lsl #16 + orr r5, r5, r5, lsr #16 + mov r6, r6, lsr #16 + orr r6, r6, r6, lsl #16 + stmia r0!, {r3, r4, r5, r6} + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + + sub r2, r2, #8 +acornscsi_out4: adds r2, r2, #4 + bmi acornscsi_out2 + ldr r4, [r1], #4 + mov r3, r4, lsl #16 + orr r3, r3, r3, lsr #16 + mov r4, r4, lsr #16 + orr r4, r4, r4, lsl #16 + stmia r0!, {r3, r4} + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + + sub r2, r2, #4 +acornscsi_out2: adds r2, r2, #2 + ldr r3, [r1], #2 + strb r3, [r0], #1 + mov r3, r3, lsr #8 + strplb r3, [r0], #1 + LOADREGS(fd, sp!, {r4 - r6, pc}) + diff -ur --new-file old/linux/drivers/acorn/scsi/acornscsi.c new/linux/drivers/acorn/scsi/acornscsi.c --- old/linux/drivers/acorn/scsi/acornscsi.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/acornscsi.c Sat Feb 7 00:55:44 1998 @@ -0,0 +1,2870 @@ +/* + * linux/arch/arm/drivers/scsi/acornscsi.c + * + * Acorn SCSI 3 driver + * By R.M.King. + * + * Abandoned using the Select and Transfer command since there were + * some nasty races between our software and the target devices that + * were not easy to solve, and the device errata had a lot of entries + * for this command, some of them quite nasty... + * + * Changelog: + * 26-Sep-1997 RMK Re-jigged to use the queue module. + * Re-coded state machine to be based on driver + * state not scsi state. Should be easier to debug. + * Added acornscsi_release to clean up properly. + * Updated proc/scsi reporting. + * 05-Oct-1997 RMK Implemented writing to SCSI devices. + * 06-Oct-1997 RMK Corrected small (non-serious) bug with the connect/ + * reconnect race condition causing a warning message. + * 12-Oct-1997 RMK Added catch for re-entering interrupt routine. + * 15-Oct-1997 RMK Improved handling of commands. + */ +#define DEBUG_NO_WRITE 1 +#define DEBUG_QUEUES 2 +#define DEBUG_DMA 4 +#define DEBUG_ABORT 8 +#define DEBUG_DISCON 16 +#define DEBUG_CONNECT 32 +#define DEBUG_PHASES 64 +#define DEBUG_WRITE 128 +#define DEBUG_LINK 256 +#define DEBUG_MESSAGES 512 +#define DEBUG_RESET 1024 +#define DEBUG_ALL (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\ + DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\ + DEBUG_DMA|DEBUG_QUEUES|DEBUG_NO_WRITE) + +/* DRIVER CONFIGURATION + * + * SCSI-II Tagged queue support. + * + * I don't have any SCSI devices that support it, so it is totally untested + * (except to make sure that it doesn't interfere with any non-tagging + * devices). It is not fully implemented either - what happens when a + * tagging device reconnects??? + * + * You can tell if you have a device that supports tagged queueing my + * cating (eg) /proc/scsi/acornscsi/0 and see if the SCSI revision is reported + * as '2 TAG'. + * + * Also note that CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE is normally set in the config + * scripts, but disabled here. Once debugged, remove the #undef, otherwise to debug, + * comment out the undef. + */ +#undef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE +/* + * SCSI-II Linked command support. + * + * The higher level code doesn't support linked commands yet, and so the option + * is undef'd here. + */ +#undef CONFIG_SCSI_ACORNSCSI_LINK +/* + * SCSI-II Synchronous transfer support. + * + * Tried and tested... + * + * SDTR_SIZE - maximum number of un-acknowledged bytes (0 = off, 12 = max) + * SDTR_PERIOD - period of REQ signal (min=125, max=1020) + * DEFAULT_PERIOD - default REQ period. + */ +#define SDTR_SIZE 12 +#define SDTR_PERIOD 125 +#define DEFAULT_PERIOD 500 + +/* + * Debugging information + * + * DEBUG - bit mask from list above + * DEBUG_TARGET - is defined to the target number if you want to debug + * a specific target. [only recon/write/dma]. + */ +#define DEBUG (DEBUG_RESET|DEBUG_WRITE|DEBUG_NO_WRITE) +/* only allow writing to SCSI device 0 */ +#define NO_WRITE 0xFE +/*#define DEBUG_TARGET 2*/ +/* + * Select timeout time (in 10ms units) + * + * This is the timeout used between the start of selection and the WD33C93 + * chip deciding that the device isn't responding. + */ +#define TIMEOUT_TIME 10 +/* + * Define this if you want to have verbose explaination of SCSI + * status/messages. + */ +#undef CONFIG_ACORNSCSI_CONSTANTS +/* + * Define this if you want to use the on board DMAC [don't remove this option] + * If not set, then use PIO mode (not currently supported). + */ +#define USE_DMAC +/* + * List of devices that the driver will recognise + */ +#define ACORNSCSI_LIST { MANU_ACORN, PROD_ACORN_SCSI } +/* + * ==================================================================================== + */ + +#ifdef DEBUG_TARGET +#define DBG(cmd,xxx...) \ + if (cmd->target == DEBUG_TARGET) { \ + xxx; \ + } +#else +#define DBG(cmd,xxx...) xxx +#endif + +#ifndef STRINGIFY +#define STRINGIFY(x) #x +#endif +#define STR(x) STRINGIFY(x) +#define NO_WRITE_STR STR(NO_WRITE) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "../../scsi/constants.h" +#include "acornscsi.h" + +#define VER_MAJOR 2 +#define VER_MINOR 0 +#define VER_PATCH 5 + +#ifndef ABORT_TAG +#define ABORT_TAG 0xd +#else +#error "Yippee! ABORT TAG is now defined! Remove this error!" +#endif + +#ifndef NO_IRQ +#define NO_IRQ 255 +#endif + +#ifdef CONFIG_SCSI_ACORNSCSI_LINK +#error SCSI2 LINKed commands not supported (yet)! +#endif + +#ifdef USE_DMAC +/* + * DMAC setup parameters + */ +#define INIT_DEVCON0 (DEVCON0_RQL|DEVCON0_EXW|DEVCON0_CMP) +#define INIT_DEVCON1 (DEVCON1_BHLD) +#define DMAC_READ (MODECON_READ) +#define DMAC_WRITE (MODECON_WRITE) +#define INIT_SBICDMA (CTRL_DMABURST) + +/* + * Size of on-board DMA buffer + */ +#define DMAC_BUFFER_SIZE 65536 +#endif + +/* + * This is used to dump the previous states of the SBIC + */ +static struct status_entry { + unsigned long when; + unsigned char ssr; + unsigned char ph; + unsigned char irq; + unsigned char unused; +} status[9][16]; +static unsigned char status_ptr[9]; + +#define ADD_STATUS(_q,_ssr,_ph,_irq) \ +({ \ + status[(_q)][status_ptr[(_q)]].when = jiffies; \ + status[(_q)][status_ptr[(_q)]].ssr = (_ssr); \ + status[(_q)][status_ptr[(_q)]].ph = (_ph); \ + status[(_q)][status_ptr[(_q)]].irq = (_irq); \ + status_ptr[(_q)] = (status_ptr[(_q)] + 1) & 15; \ +}) + +unsigned int sdtr_period = SDTR_PERIOD; +unsigned int sdtr_size = SDTR_SIZE; + +static struct proc_dir_entry proc_scsi_acornscsi = { + PROC_SCSI_EATA, 9, "acornscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +static void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result); +static int acornscsi_reconnect_finish (AS_Host *host); +static void acornscsi_dma_cleanup (AS_Host *host); +static void acornscsi_abortcmd (AS_Host *host, unsigned char tag); + +/* ==================================================================================== + * Miscellaneous + */ + +static inline void +sbic_arm_write (unsigned int io_port, int reg, int value) +{ + outb_t (reg, io_port); + outb_t (value, io_port + 4); +} + +#define sbic_arm_writenext(io,val) \ + outb_t ((val), (io) + 4) + +static inline +int sbic_arm_read (unsigned int io_port, int reg) +{ + if(reg == ASR) + return inl_t(io_port) & 255; + outb_t (reg, io_port); + return inl_t(io_port + 4) & 255; +} + +#define sbic_arm_readnext(io) \ + inb_t((io) + 4) + +#ifdef USE_DMAC +#define dmac_read(io_port,reg) \ + inb ((io_port) + (reg)) + +#define dmac_write(io_port,reg,value) \ + ({ outb ((value), (io_port) + (reg)); }) + +#define dmac_clearintr(io_port) \ + ({ outb (0, (io_port)); }) + +static inline +unsigned int dmac_address (unsigned int io_port) +{ + return dmac_read (io_port, TXADRHI) << 16 | + dmac_read (io_port, TXADRMD) << 8 | + dmac_read (io_port, TXADRLO); +} +#endif + +static +unsigned long acornscsi_sbic_xfcount (AS_Host *host) +{ + unsigned long length; + + length = sbic_arm_read (host->scsi.io_port, TRANSCNTH) << 16; + length |= sbic_arm_readnext (host->scsi.io_port) << 8; + length |= sbic_arm_readnext (host->scsi.io_port); + + return length; +} + +static +int acornscsi_sbic_issuecmd (AS_Host *host, int command) +{ + int asr; + + do { + asr = sbic_arm_read (host->scsi.io_port, ASR); + } while (asr & ASR_CIP); + + sbic_arm_write (host->scsi.io_port, CMND, command); + + return 0; +} + +static void +acornscsi_csdelay (unsigned int cs) +{ + unsigned long target_jiffies, flags; + + target_jiffies = jiffies + 1 + cs * HZ / 100; + + save_flags (flags); + sti (); + + while (jiffies < target_jiffies) barrier(); + + restore_flags (flags); +} + +static +void acornscsi_resetcard (AS_Host *host) +{ + unsigned int i; + + /* assert reset line */ + host->card.page_reg = 0x80; + outb (host->card.page_reg, host->card.io_page); + + /* wait 3 cs. SCSI standard says 25ms. */ + acornscsi_csdelay (3); + + host->card.page_reg = 0; + outb (host->card.page_reg, host->card.io_page); + + /* + * Should get a reset from the card + */ + while (!(inb (host->card.io_intr) & 8)); + sbic_arm_read (host->scsi.io_port, ASR); + sbic_arm_read (host->scsi.io_port, SSR); + + /* setup sbic - WD33C93A */ + sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + + /* + * Command should cause a reset interrupt + */ + while (!(inb (host->card.io_intr) & 8)); + sbic_arm_read (host->scsi.io_port, ASR); + if (sbic_arm_read (host->scsi.io_port, SSR) != 0x01) + printk (KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", + host->host->host_no); + + sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + + host->card.page_reg = 0x40; + outb (host->card.page_reg, host->card.io_page); + +#ifdef USE_DMAC + /* setup dmac - uPC71071 */ + dmac_write (host->dma.io_port, INIT, 0); + dmac_write (host->dma.io_port, INIT, INIT_8BIT); + dmac_write (host->dma.io_port, CHANNEL, CHANNEL_0); + dmac_write (host->dma.io_port, DEVCON0, INIT_DEVCON0); + dmac_write (host->dma.io_port, DEVCON1, INIT_DEVCON1); +#else + dmac_write (host->dma.io_port, INIT, 0); +#endif + + host->SCpnt = NULL; + host->scsi.phase = PHASE_IDLE; + host->scsi.disconnectable = 0; + + for (i = 0; i < 8; i++) { + host->busyluns[i] = 0; + host->device[i].sync_state = SYNC_NEGOCIATE; + host->device[i].disconnect_ok = 1; + } + + /* wait 25 cs. SCSI standard says 250ms. */ + acornscsi_csdelay (25); +} + +/*============================================================================================= + * Utility routines (eg. debug) + */ +#ifdef CONFIG_ACORNSCSI_CONSTANTS +static char *acornscsi_interrupttype[] = { + "rst", "suc", "p/a", "3", + "term", "5", "6", "7", + "serv", "9", "a", "b", + "c", "d", "e", "f" +}; + +static signed char acornscsi_map[] = { + 0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 2, -1, -1, -1, -1, 3, -1, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, -1, -1, -1, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 15, 16, 17, 18, 19, -1, -1, 20, 4, 5, 6, 7, 8, 9, 10, 11, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 21, 22, -1, -1, -1, 23, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static char *acornscsi_interruptcode[] = { + /* 0 */ + "reset - normal mode", /* 00 */ + "reset - advanced mode", /* 01 */ + + /* 2 */ + "sel", /* 11 */ + "sel+xfer", /* 16 */ + "data-out", /* 18 */ + "data-in", /* 19 */ + "cmd", /* 1A */ + "stat", /* 1B */ + "??-out", /* 1C */ + "??-in", /* 1D */ + "msg-out", /* 1E */ + "msg-in", /* 1F */ + + /* 12 */ + "/ACK asserted", /* 20 */ + "save-data-ptr", /* 21 */ + "{re}sel", /* 22 */ + + /* 15 */ + "inv cmd", /* 40 */ + "unexpected disconnect", /* 41 */ + "sel timeout", /* 42 */ + "P err", /* 43 */ + "P err+ATN", /* 44 */ + "bad status byte", /* 47 */ + + /* 21 */ + "resel, no id", /* 80 */ + "resel", /* 81 */ + "discon", /* 85 */ +}; + +static +void print_scsi_status (unsigned int ssr) +{ + if (acornscsi_map[ssr] != -1) + printk ("%s:%s", + acornscsi_interrupttype[(ssr >> 4)], + acornscsi_interruptcode[acornscsi_map[ssr]]); + else + printk ("%X:%X", ssr >> 4, ssr & 0x0f); +} +#endif + +static +void print_sbic_status (int asr, int ssr, int cmdphase) +{ +#ifdef CONFIG_ACORNSCSI_CONSTANTS + printk ("sbic: %c%c%c%c%c%c ", + asr & ASR_INT ? 'I' : 'i', + asr & ASR_LCI ? 'L' : 'l', + asr & ASR_BSY ? 'B' : 'b', + asr & ASR_CIP ? 'C' : 'c', + asr & ASR_PE ? 'P' : 'p', + asr & ASR_DBR ? 'D' : 'd'); + printk ("scsi: "); + print_scsi_status (ssr); + printk (" ph %02X\n", cmdphase); +#else + printk ("sbic: %02X scsi: %X:%X ph: %02X\n", + asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase); +#endif +} + +static +void acornscsi_dumplog (AS_Host *host, int target) +{ + unsigned int prev; + do { + signed int statptr; + + printk ("%c:", target == 8 ? 'H' : ('0' + target)); + statptr = status_ptr[target] - 10; + + if (statptr < 0) + statptr += 16; + + prev = status[target][statptr].when; + + for (; statptr != status_ptr[target]; statptr = (statptr + 1) & 15) { + if (status[target][statptr].when) { +#ifdef CONFIG_ACORNSCSI_CONSTANTS + printk ("%c%02X:S=", + status[target][statptr].irq ? '-' : ' ', + status[target][statptr].ph); + print_scsi_status (status[target][statptr].ssr); +#else + printk ("%c%02X:%02X", + status[target][statptr].irq ? '-' : ' ', + status[target][statptr].ph, + status[target][statptr].ssr); +#endif + printk ("+%02ld", + (status[target][statptr].when - prev) < 100 ? + (status[target][statptr].when - prev) : 99); + prev = status[target][statptr].when; + } + } + printk ("\n"); + if (target == 8) + break; + target = 8; + } while (1); +} + +static +char acornscsi_target (AS_Host *host) +{ + if (host->SCpnt) + return '0' + host->SCpnt->target; + return 'H'; +} + +#ifdef USE_DMAC +static +void acornscsi_dumpdma (AS_Host *host, char *where) +{ + unsigned int mode, addr, len; + + mode = dmac_read (host->dma.io_port, MODECON); + addr = dmac_address (host->dma.io_port); + len = dmac_read (host->dma.io_port, TXCNTHI) << 8 | + dmac_read (host->dma.io_port, TXCNTLO); + + printk ("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ", + host->host->host_no, where, + mode, addr, (len + 1) & 0xffff, + dmac_read (host->dma.io_port, MASKREG)); + + printk ("DMA @%06x, ", host->dma.start_addr); + printk ("BH @%p +%04x, ", host->scsi.SCp.ptr, + host->scsi.SCp.this_residual); + printk ("DT @+%04x ST @+%04x", host->dma.transferred, + host->scsi.SCp.have_data_in); + printk ("\n"); +} +#endif + +/* + * Prototype: cmdtype_t acornscsi_cmdtype (int command) + * Purpose : differentiate READ from WRITE from other commands + * Params : command - command to interpret + * Returns : CMD_READ - command reads data, + * CMD_WRITE - command writes data, + * CMD_MISC - everything else + */ +static inline +cmdtype_t acornscsi_cmdtype (int command) +{ + switch (command) { + case WRITE_6: case WRITE_10: case WRITE_12: + return CMD_WRITE; + case READ_6: case READ_10: case READ_12: + return CMD_READ; + default: + return CMD_MISC; + } +} + +/* + * Prototype: int acornscsi_datadirection (int command) + * Purpose : differentiate between commands that have a DATA IN phase + * and a DATA OUT phase + * Params : command - command to interpret + * Returns : DATADIR_OUT - data out phase expected + * DATADIR_IN - data in phase expected + */ +static +datadir_t acornscsi_datadirection (int command) +{ + switch (command) { + case CHANGE_DEFINITION: case COMPARE: case COPY: + case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT: + case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER: + case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case WRITE_6: case WRITE_10: case WRITE_VERIFY: + case UPDATE_BLOCK: case WRITE_LONG: case WRITE_SAME: + case SEARCH_HIGH_12: case SEARCH_EQUAL_12: case SEARCH_LOW_12: + case WRITE_12: case WRITE_VERIFY_12: case SET_WINDOW: + case MEDIUM_SCAN: case SEND_VOLUME_TAG: case 0xea: + return DATADIR_OUT; + default: + return DATADIR_IN; + } +} + +/* + * Purpose : provide values for synchronous transfers with 33C93. + * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting + * Modified by Russell King for 8MHz WD33C93A + */ +static struct sync_xfer_tbl { + unsigned int period_ns; + unsigned char reg_value; +} sync_xfer_table[] = { + { 1, 0x20 }, { 249, 0x20 }, { 374, 0x30 }, + { 499, 0x40 }, { 624, 0x50 }, { 749, 0x60 }, + { 874, 0x70 }, { 999, 0x00 }, { 0, 0 } +}; + +/* + * Prototype: int acornscsi_getperiod (unsigned char syncxfer) + * Purpose : period for the synchronous transfer setting + * Params : syncxfer SYNCXFER register value + * Returns : period in ns. + */ +static +int acornscsi_getperiod (unsigned char syncxfer) +{ + int i; + + syncxfer &= 0xf0; + if (syncxfer == 0x10) + syncxfer = 0; + + for (i = 1; sync_xfer_table[i].period_ns; i++) + if (syncxfer == sync_xfer_table[i].reg_value) + return sync_xfer_table[i].period_ns; + return 0; +} + +/* + * Prototype: int round_period (unsigned int period) + * Purpose : return index into above table for a required REQ period + * Params : period - time (ns) for REQ + * Returns : table index + * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting + */ +static inline +int round_period (unsigned int period) +{ + int i; + + for (i = 1; sync_xfer_table[i].period_ns; i++) { + if ((period <= sync_xfer_table[i].period_ns) && + (period > sync_xfer_table[i - 1].period_ns)) + return i; + } + return 7; +} + +/* + * Prototype: unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) + * Purpose : calculate value for 33c93s SYNC register + * Params : period - time (ns) for REQ + * offset - offset in bytes between REQ/ACK + * Returns : value for SYNC register + * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting + */ +static +unsigned char calc_sync_xfer (unsigned int period, unsigned int offset) +{ + return sync_xfer_table[round_period(period)].reg_value | + ((offset < SDTR_SIZE) ? offset : SDTR_SIZE); +} + +/* ==================================================================================== + * Command functions + */ +/* + * Function: acornscsi_kick (AS_Host *host) + * Purpose : kick next command to interface + * Params : host - host to send command to + * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING + * Notes : interrupts are always disabled! + */ +static +intr_ret_t acornscsi_kick (AS_Host *host) +{ + int from_queue = 0; + Scsi_Cmnd *SCpnt; + + /* first check to see if a command is waiting to be executed */ + SCpnt = host->origSCpnt; + host->origSCpnt = NULL; + + /* retrieve next command */ + if (!SCpnt) { + SCpnt = queue_remove_exclude (&host->queues.issue, host->busyluns); + if (!SCpnt) + return INTR_IDLE; + + from_queue = 1; + } + + if (host->scsi.disconnectable && host->SCpnt) { + queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); + host->scsi.disconnectable = 0; +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + DBG(host->SCpnt, printk ("scsi%d.%c: moved command to disconnected queue\n", + host->host->host_no, acornscsi_target (host))); +#endif + host->SCpnt = NULL; + } + + /* + * If we have an interrupt pending, then we may have been reselected. + * In this case, we don't want to write to the registers + */ + if (!(sbic_arm_read (host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) { + sbic_arm_write (host->scsi.io_port, DESTID, SCpnt->target); + sbic_arm_write (host->scsi.io_port, CMND, CMND_SELWITHATN); + } + + /* + * claim host busy - all of these must happen atomically wrt + * our interrupt routine. Failure means command loss. + */ + host->scsi.phase = PHASE_CONNECTING; + host->SCpnt = SCpnt; + host->scsi.SCp = SCpnt->SCp; + host->dma.xfer_setup = 0; + host->dma.xfer_required = 0; + +#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT)) + DBG(SCpnt,printk ("scsi%d.%c: starting cmd %02X\n", + host->host->host_no, '0' + SCpnt->target, + SCpnt->cmnd[0])); +#endif + + if (from_queue) { +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + /* + * tagged queueing - allocate a new tag to this command + */ + if (SCpnt->device->tagged_queue) { + SCpnt->device->current_tag += 1; + if (SCpnt->device->current_tag == 0) + SCpnt->device->current_tag = 1; + SCpnt->tag = SCpnt->device->current_tag; + } else +#endif + set_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + + host->stats.removes += 1; + + switch (acornscsi_cmdtype (SCpnt->cmnd[0])) { + case CMD_WRITE: + host->stats.writes += 1; + break; + case CMD_READ: + host->stats.reads += 1; + break; + case CMD_MISC: + host->stats.miscs += 1; + break; + } + } + + return INTR_PROCESSING; +} + +/* + * Function: void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) + * Purpose : complete processing for command + * Params : host - interface that completed + * result - driver byte of result + */ +static +void acornscsi_done (AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result) +{ + Scsi_Cmnd *SCpnt = *SCpntp; + + /* clean up */ + sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + + host->stats.fins += 1; + + if (SCpnt) { + *SCpntp = NULL; + + acornscsi_dma_cleanup (host); + + SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status; + + /* + * In theory, this should not happen. In practice, it seems to. + * Only trigger an error if the device attempts to report all happy + * but with untransferred buffers... If we don't do something, then + * data loss will occur. Should we check SCpnt->underflow here? + * It doesn't appear to be set to something meaningful by the higher + * levels all the time. + */ + if (host->scsi.SCp.ptr && result == DID_OK && + acornscsi_cmdtype (SCpnt->cmnd[0]) != CMD_MISC) { + switch (status_byte (SCpnt->result)) { + case CHECK_CONDITION: + case COMMAND_TERMINATED: + case BUSY: + case QUEUE_FULL: + case RESERVATION_CONFLICT: + break; + + default: + printk (KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=", + host->host->host_no, SCpnt->result); + print_command (SCpnt->cmnd); + acornscsi_dumpdma (host, "done"); + acornscsi_dumplog (host, SCpnt->target); + SCpnt->result &= 0xffff; + SCpnt->result |= DID_ERROR << 16; + } + } + + if (!SCpnt->scsi_done) + panic ("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no); + + clear_bit (SCpnt->target * 8 + SCpnt->lun, host->busyluns); + + SCpnt->scsi_done (SCpnt); + } else + printk ("scsi%d: null command in acornscsi_done", host->host->host_no); + + host->scsi.phase = PHASE_IDLE; +} + +/* ==================================================================================== + * DMA routines + */ +/* + * Purpose : update SCSI Data Pointer + * Notes : this will only be one SG entry or less + */ +static +void acornscsi_data_updateptr (AS_Host *host, Scsi_Pointer *SCp, unsigned int length) +{ + SCp->ptr += length; + SCp->this_residual -= length; + + if (!SCp->this_residual) { + if (SCp->buffers_residual) { + SCp->buffer++; + SCp->buffers_residual--; + SCp->ptr = (char *)SCp->buffer->address; + SCp->this_residual = SCp->buffer->length; + } else + SCp->ptr = NULL; + } +} + +/* + * Prototype: void acornscsi_data_read (AS_Host *host, char *ptr, + * unsigned int start_addr, unsigned int length) + * Purpose : read data from DMA RAM + * Params : host - host to transfer from + * ptr - DRAM address + * start_addr - host mem address + * length - number of bytes to transfer + * Notes : this will only be one SG entry or less + */ +static +void acornscsi_data_read (AS_Host *host, char *ptr, + unsigned int start_addr, unsigned int length) +{ + extern void __acornscsi_in (int port, char *buf, int len); + unsigned int page, offset, len = length; + + page = (start_addr >> 12); + offset = start_addr & ((1 << 12) - 1); + + outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + + while (len > 0) { + unsigned int this_len; + + if (len + offset > (1 << 12)) + this_len = (1 << 12) - offset; + else + this_len = len; + + __acornscsi_in (host->card.io_ram + (offset << 1), ptr, this_len); + + offset += this_len; + ptr += this_len; + len -= this_len; + + if (offset == (1 << 12)) { + offset = 0; + page ++; + outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + } + } + outb (host->card.page_reg, host->card.io_page); +} + +/* + * Prototype: void acornscsi_data_write (AS_Host *host, char *ptr, + * unsigned int start_addr, unsigned int length) + * Purpose : write data to DMA RAM + * Params : host - host to transfer from + * ptr - DRAM address + * start_addr - host mem address + * length - number of bytes to transfer + * Notes : this will only be one SG entry or less + */ +static +void acornscsi_data_write (AS_Host *host, char *ptr, + unsigned int start_addr, unsigned int length) +{ + extern void __acornscsi_out (int port, char *buf, int len); + unsigned int page, offset, len = length; + + page = (start_addr >> 12); + offset = start_addr & ((1 << 12) - 1); + + outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + + while (len > 0) { + unsigned int this_len; + + if (len + offset > (1 << 12)) + this_len = (1 << 12) - offset; + else + this_len = len; + + __acornscsi_out (host->card.io_ram + (offset << 1), ptr, this_len); + + offset += this_len; + ptr += this_len; + len -= this_len; + + if (offset == (1 << 12)) { + offset = 0; + page ++; + outb ((page & 0x3f) | host->card.page_reg, host->card.io_page); + } + } + outb (host->card.page_reg, host->card.io_page); +} + +/* ========================================================================================= + * On-board DMA routines + */ +#ifdef USE_DMAC +/* + * Prototype: void acornscsi_dmastop (AS_Host *host) + * Purpose : stop all DMA + * Params : host - host on which to stop DMA + * Notes : This is called when leaving DATA IN/OUT phase, + * or when interface is RESET + */ +static inline +void acornscsi_dma_stop (AS_Host *host) +{ + dmac_write (host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr (host->dma.io_intr_clear); + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "stop")); +#endif +} + +/* + * Function: void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) + * Purpose : setup DMA controller for data transfer + * Params : host - host to setup + * direction - data transfer direction + * Notes : This is called when entering DATA I/O phase, not + * while we're in a DATA I/O phase + */ +static +void acornscsi_dma_setup (AS_Host *host, dmadir_t direction) +{ + unsigned int address, length, mode; + + host->dma.direction = direction; + + dmac_write (host->dma.io_port, MASKREG, MASK_ON); + + if (direction == DMA_OUT) { +#if (DEBUG & DEBUG_NO_WRITE) + if (NO_WRITE & (1 << host->SCpnt->target)) { + printk (KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n", + host->host->host_no, acornscsi_target (host)); + return; + } +#endif + mode = DMAC_WRITE; + } else + mode = DMAC_READ; + + /* + * Allocate some buffer space, limited to half the buffer size + */ + length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + if (length) { + host->dma.start_addr = address = host->dma.free_addr; + host->dma.free_addr = (host->dma.free_addr + length) & + (DMAC_BUFFER_SIZE - 1); + + /* + * Transfer data to DMA memory + */ + if (direction == DMA_OUT) + acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + length); + + length -= 1; + dmac_write (host->dma.io_port, TXCNTLO, length); + dmac_write (host->dma.io_port, TXCNTHI, length >> 8); + dmac_write (host->dma.io_port, TXADRLO, address); + dmac_write (host->dma.io_port, TXADRMD, address >> 8); + dmac_write (host->dma.io_port, TXADRHI, 0); + dmac_write (host->dma.io_port, MODECON, mode); + dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "strt")); +#endif + host->dma.xfer_setup = 1; + } +} + +/* + * Function: void acornscsi_dma_cleanup (AS_Host *host) + * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct + * Params : host - host to finish + * Notes : This is called when a command is: + * terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT + * : This must not return until all transfers are completed. + */ +static +void acornscsi_dma_cleanup (AS_Host *host) +{ + dmac_write (host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr (host->dma.io_intr_clear); + + /* + * Check for a pending transfer + */ + if (host->dma.xfer_required) { + host->dma.xfer_required = 0; + if (host->dma.direction == DMA_IN) + acornscsi_data_read (host, host->dma.xfer_ptr, + host->dma.xfer_start, host->dma.xfer_length); + } + + /* + * Has a transfer been setup? + */ + if (host->dma.xfer_setup) { + unsigned int transferred; + + host->dma.xfer_setup = 0; + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "clup")); +#endif + + /* + * Calculate number of bytes transferred from DMA. + */ + transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + host->dma.transferred += transferred; + + if (host->dma.direction == DMA_IN) + acornscsi_data_read (host, host->scsi.SCp.ptr, + host->dma.start_addr, transferred); + + /* + * Update SCSI pointers + */ + acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + } +} + +/* + * Function: void acornscsi_dmacintr (AS_Host *host) + * Purpose : handle interrupts from DMAC device + * Params : host - host to process + * Notes : If reading, we schedule the read to main memory & + * allow the transfer to continue. + * : If writing, we fill the onboard DMA memory from main + * memory. + * : Called whenever DMAC finished it's current transfer. + */ +static +void acornscsi_dma_intr (AS_Host *host) +{ + unsigned int address, length, transferred; + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "inti")); +#endif + + dmac_write (host->dma.io_port, MASKREG, MASK_ON); + dmac_clearintr (host->dma.io_intr_clear); + + /* + * Calculate amount transferred via DMA + */ + transferred = dmac_address (host->dma.io_port) - host->dma.start_addr; + host->dma.transferred += transferred; + + /* + * Schedule DMA transfer off board + */ + if (host->dma.direction == DMA_IN) { + host->dma.xfer_start = host->dma.start_addr; + host->dma.xfer_length = transferred; + host->dma.xfer_ptr = host->scsi.SCp.ptr; + host->dma.xfer_required = 1; + } + + acornscsi_data_updateptr (host, &host->scsi.SCp, transferred); + + /* + * Allocate some buffer space, limited to half the on-board RAM size + */ + length = min (host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); + if (length) { + host->dma.start_addr = address = host->dma.free_addr; + host->dma.free_addr = (host->dma.free_addr + length) & + (DMAC_BUFFER_SIZE - 1); + + /* + * Transfer data to DMA memory + */ + if (host->dma.direction == DMA_OUT) + acornscsi_data_write (host, host->scsi.SCp.ptr, host->dma.start_addr, + length); + + length -= 1; + dmac_write (host->dma.io_port, TXCNTLO, length); + dmac_write (host->dma.io_port, TXCNTHI, length >> 8); + dmac_write (host->dma.io_port, TXADRLO, address); + dmac_write (host->dma.io_port, TXADRMD, address >> 8); + dmac_write (host->dma.io_port, TXADRHI, 0); + dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + +#if (DEBUG & DEBUG_DMA) + DBG(host->SCpnt, acornscsi_dumpdma (host, "into")); +#endif + } else { + host->dma.xfer_setup = 0; +#if 0 + /* + * If the interface still wants more, then this is an error. + * We give it another byte, but we also attempt to raise an + * attention condition. We continue giving one byte until + * the device recognises the attention. + */ + if (dmac_read (host->dma.io_port, STATUS) & STATUS_RQ0) { + acornscsi_abortcmd (host, host->SCpnt->tag); + + dmac_write (host->dma.io_port, TXCNTLO, 0); + dmac_write (host->dma.io_port, TXCNTHI, 0); + dmac_write (host->dma.io_port, TXADRLO, 0); + dmac_write (host->dma.io_port, TXADRMD, 0); + dmac_write (host->dma.io_port, TXADRHI, 0); + dmac_write (host->dma.io_port, MASKREG, MASK_OFF); + } +#endif + } +} + +/* + * Function: void acornscsi_dma_xfer (AS_Host *host) + * Purpose : transfer data between AcornSCSI and memory + * Params : host - host to process + */ +static +void acornscsi_dma_xfer (AS_Host *host) +{ + host->dma.xfer_required = 0; + + if (host->dma.direction == DMA_IN) + acornscsi_data_read (host, host->dma.xfer_ptr, + host->dma.xfer_start, host->dma.xfer_length); +} + +/* + * Function: void acornscsi_dma_adjust (AS_Host *host) + * Purpose : adjust DMA pointers & count for bytes transfered to + * SBIC but not SCSI bus. + * Params : host - host to adjust DMA count for + */ +static +void acornscsi_dma_adjust (AS_Host *host) +{ + if (host->dma.xfer_setup) { + signed long transferred; +#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) + DBG(host->SCpnt, acornscsi_dumpdma (host, "adji")); +#endif + /* + * Calculate correct DMA address - DMA is ahead of SCSI bus while + * writing. + * host->scsi.SCp.have_data_in is the number of bytes + * actually transferred to/from the SCSI bus. + * host->dma.transferred is the number of bytes transferred + * over DMA since host->dma.start_addr was last set. + * + * real_dma_addr = host->dma.start_addr + host->scsi.SCp.have_data_in + * - host->dma.transferred + */ + transferred = host->scsi.SCp.have_data_in - host->dma.transferred; + if (transferred < 0) + printk ("scsi%d.%c: Ack! DMA write correction %ld < 0!\n", + host->host->host_no, acornscsi_target (host), transferred); + else if (transferred == 0) + host->dma.xfer_setup = 0; + else { + transferred += host->dma.start_addr; + dmac_write (host->dma.io_port, TXADRLO, transferred); + dmac_write (host->dma.io_port, TXADRMD, transferred >> 8); + dmac_write (host->dma.io_port, TXADRHI, transferred >> 16); +#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) + DBG(host->SCpnt, acornscsi_dumpdma (host, "adjo")); +#endif + } + } +} +#endif + +/* ========================================================================================= + * Data I/O + */ +/* + * Function: void acornscsi_sendcommand (AS_Host *host) + * Purpose : send a command to a target + * Params : host - host which is connected to target + */ +static +void acornscsi_sendcommand (AS_Host *host) +{ + Scsi_Cmnd *SCpnt = host->SCpnt; + unsigned int asr; + unsigned char *cmdptr, *cmdend; + + sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext (host->scsi.io_port, 0); + sbic_arm_writenext (host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command); + acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + + cmdptr = SCpnt->cmnd + host->scsi.SCp.sent_command; + cmdend = SCpnt->cmnd + SCpnt->cmd_len; + + while (cmdptr < cmdend) { + asr = sbic_arm_read (host->scsi.io_port, ASR); + if (asr & ASR_DBR) + sbic_arm_write (host->scsi.io_port, DATA, *cmdptr++); + else if (asr & ASR_INT) + break; + } + if (cmdptr >= cmdend) + host->scsi.SCp.sent_command = cmdptr - SCpnt->cmnd; + host->scsi.phase = PHASE_COMMAND; +} + +static +void acornscsi_sendmessage (AS_Host *host) +{ + unsigned int message_length = msgqueue_msglength (&host->scsi.msgs); + int msglen; + char *msg; + +#if (DEBUG & DEBUG_MESSAGES) + printk ("scsi%d.%c: sending message ", + host->host->host_no, acornscsi_target (host)); +#endif + + switch (message_length) { + case 0: + acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + sbic_arm_write (host->scsi.io_port, DATA, NOP); + host->scsi.last_message = NOP; +#if (DEBUG & DEBUG_MESSAGES) + printk ("NOP"); +#endif + break; + + case 1: + acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); + msg = msgqueue_getnextmsg (&host->scsi.msgs, &msglen); + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + sbic_arm_write (host->scsi.io_port, DATA, msg[0]); + host->scsi.last_message = msg[0]; +#if (DEBUG & DEBUG_MESSAGES) + print_msg (msg); +#endif + break; + + default: + /* + * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14) + * 'When a target sends this (MESSAGE_REJECT) message, it + * shall change to MESSAGE IN phase and send this message + * prior to requesting additional message bytes from the + * initiator. This provides an interlock so that the + * initiator can determine which message byte is rejected. + */ + sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0); + sbic_arm_writenext (host->scsi.io_port, 0); + sbic_arm_writenext (host->scsi.io_port, message_length); + acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + + while ((msg = msgqueue_getnextmsg (&host->scsi.msgs, &msglen)) != NULL) { + unsigned int asr, i; +#if (DEBUG & DEBUG_MESSAGES) + print_msg (msg); +#endif + for (i = 0; i < msglen;) { + asr = sbic_arm_read (host->scsi.io_port, ASR); + if (asr & ASR_DBR) + sbic_arm_write (host->scsi.io_port, DATA, msg[i++]); + if (asr & ASR_INT) + break; + } + host->scsi.last_message = msg[0]; + if (msg[0] == EXTENDED_MESSAGE) + host->scsi.last_message |= msg[2] << 8; + if (asr & ASR_INT) + break; + } + break; + } +#if (DEBUG & DEBUG_MESSAGES) + printk ("\n"); +#endif +} + +/* + * Function: void acornscsi_readstatusbyte (AS_Host *host) + * Purpose : Read status byte from connected target + * Params : host - host connected to target + */ +static +void acornscsi_readstatusbyte (AS_Host *host) +{ + acornscsi_sbic_issuecmd (host, CMND_XFERINFO|CMND_SBT); + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + + host->scsi.SCp.Status = sbic_arm_read (host->scsi.io_port, DATA); +} + +/* + * Function: unsigned char acornscsi_readmessagebyte (AS_Host *host) + * Purpose : Read one message byte from connected target + * Params : host - host connected to target + */ +static +unsigned char acornscsi_readmessagebyte (AS_Host *host) +{ + unsigned char message; + + acornscsi_sbic_issuecmd (host, CMND_XFERINFO | CMND_SBT); + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0); + + message = sbic_arm_read (host->scsi.io_port, DATA); + + /* wait for MSGIN-XFER-PAUSED */ + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); + sbic_arm_read (host->scsi.io_port, SSR); + + return message; +} + +/* + * Function: void acornscsi_message (AS_Host *host) + * Purpose : Read complete message from connected target & action message + * Params : host - host connected to target + */ +static +void acornscsi_message (AS_Host *host) +{ + unsigned char message[16]; + unsigned int msgidx = 0, msglen = 1; + + do { + message[msgidx] = acornscsi_readmessagebyte (host); + + switch (msgidx) { + case 0: + if (message[0] == EXTENDED_MESSAGE || + (message[0] >= 0x20 && message[0] <= 0x2f)) + msglen = 2; + break; + + case 1: + if (message[0] == EXTENDED_MESSAGE) + msglen += message[msgidx]; + break; + } + msgidx += 1; + if (msgidx < msglen) { + acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + + /* wait for next msg-in */ + while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_INT) == 0); + sbic_arm_read (host->scsi.io_port, SSR); + } + } while (msgidx < msglen); + +#if (DEBUG & DEBUG_MESSAGES) + printk (KERN_DEBUG "scsi%d.%c: message in: ", + host->host->host_no, acornscsi_target (host)); + print_msg (message); + printk ("\n"); +#endif + + if (host->scsi.phase == PHASE_RECONNECTED) { + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17) + * 'Whenever a target reconnects to an initiator to continue + * a tagged I/O process, the SIMPLE QUEUE TAG message shall + * be sent immediately following the IDENTIFY message...' + */ + if (message[0] == SIMPLE_QUEUE_TAG) + host->scsi.reconnected.tag = message[1]; + if (acornscsi_reconnect_finish (host)) + host->scsi.phase = PHASE_MSGIN; + } + + switch (message[0]) { + case ABORT: + case ABORT_TAG: + case COMMAND_COMPLETE: + if (host->scsi.phase != PHASE_STATUSIN) + printk (KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n", + host->host->host_no, acornscsi_target (host)); + host->scsi.phase = PHASE_DONE; + host->scsi.SCp.Message = message[0]; + break; + + case SAVE_POINTERS: + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20) + * 'The SAVE DATA POINTER message is sent from a target to + * direct the initiator to copy the active data pointer to + * the saved data pointer for the current I/O process. + */ + acornscsi_dma_cleanup (host); + host->SCpnt->SCp = host->scsi.SCp; + host->SCpnt->SCp.sent_command = 0; + host->scsi.phase = PHASE_MSGIN; + break; + + case RESTORE_POINTERS: + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19) + * 'The RESTORE POINTERS message is sent from a target to + * direct the initiator to copy the most recently saved + * command, data, and status pointers for the I/O process + * to the corresponding active pointers. The command and + * status pointers shall be restored to the beginning of + * the present command and status areas.' + */ + acornscsi_dma_cleanup (host); + host->scsi.SCp = host->SCpnt->SCp; + host->scsi.phase = PHASE_MSGIN; + break; + + case DISCONNECT: + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2) + * 'On those occasions when an error or exception condition occurs + * and the target elects to repeat the information transfer, the + * target may repeat the transfer either issuing a RESTORE POINTERS + * message or by disconnecting without issuing a SAVE POINTERS + * message. When reconnection is completed, the most recent + * saved pointer values are restored.' + */ + acornscsi_dma_cleanup (host); + host->scsi.phase = PHASE_DISCONNECT; + break; + + case MESSAGE_REJECT: +#if 0 /* this isn't needed any more */ + /* + * If we were negociating sync transfer, we don't yet know if + * this REJECT is for the sync transfer or for the tagged queue/wide + * transfer. Re-initiate sync transfer negociation now, and if + * we got a REJECT in response to SDTR, then it'll be set to DONE. + */ + if (host->device[host->SCpnt->target].sync_state == SYNC_SENT_REQUEST) + host->device[host->SCpnt->target].sync_state = SYNC_NEGOCIATE; +#endif + + /* + * If we have any messages waiting to go out, then assert ATN now + */ + if (msgqueue_msglength (&host->scsi.msgs)) + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + + switch (host->scsi.last_message) { +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + /* + * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17) + * If a target does not implement tagged queuing and a queue tag + * message is received, it shall respond with a MESSAGE REJECT + * message and accept the I/O process as if it were untagged. + */ + printk (KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", + host->host->host_no, acornscsi_target (host)); + host->SCpnt->device->tagged_queue = 0; + set_bit (host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); + break; +#endif + case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8): + /* + * Target can't handle synchronous transfers + */ + printk (KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", + host->host->host_no, acornscsi_target (host)); + host->device[host->SCpnt->target].sync_xfer = SYNCHTRANSFER_2DBA; + host->device[host->SCpnt->target].sync_state = SYNC_ASYNCHRONOUS; + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + break; + + default: + break; + } + break; + + case QUEUE_FULL: + /* TODO: target queue is full */ + break; + + case SIMPLE_QUEUE_TAG: + /* tag queue reconnect... message[1] = queue tag. Print something to indicate something happened! */ + printk ("scsi%d.%c: reconnect queue tag %02X\n", + host->host->host_no, acornscsi_target (host), + message[1]); + break; + + case EXTENDED_MESSAGE: + switch (message[2]) { +#ifdef CONFIG_SCSI_ACORNSCSI_SYNC + case EXTENDED_SDTR: + if (host->device[host->SCpnt->target].sync_state == SYNC_SENT_REQUEST) { + /* + * We requested synchronous transfers. This isn't quite right... + * We can only say if this succeeded if we proceed on to execute the + * command from this message. If we get a MESSAGE PARITY ERROR, + * and the target retries fail, then we fallback to asynchronous mode + */ + host->device[host->SCpnt->target].sync_state = SYNC_COMPLETED; + printk (KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", + host->host->host_no, acornscsi_target(host), + message[4], message[3] * 4); + host->device[host->SCpnt->target].sync_xfer = + calc_sync_xfer (message[3] * 4, message[4]); + } else { + unsigned char period, length; + /* + * Target requested synchronous transfers. The agreement is only + * to be in operation AFTER the target leaves message out phase. + */ + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + period = max (message[3], sdtr_period / 4); + length = min (message[4], sdtr_size); + msgqueue_addmsg (&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, + EXTENDED_SDTR, period, length); + host->device[host->SCpnt->target].sync_xfer = + calc_sync_xfer (period * 4, length); + } + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + break; +#else + /* We do not accept synchronous transfers. Respond with a + * MESSAGE_REJECT. + */ +#endif + + case EXTENDED_WDTR: + /* The WD33C93A is only 8-bit. We respond with a MESSAGE_REJECT + * to a wide data transfer request. + */ + default: + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + msgqueue_flush (&host->scsi.msgs); + msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + break; + } + break; + +#ifdef CONFIG_SCSI_ACORNSCSI_LINK + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: + /* + * We don't support linked commands yet + */ + if (0) { +#if (DEBUG & DEBUG_LINK) + printk (KERN_DEBUG "scsi%d.%c: lun %d tag %d linked command complete\n", + host->host->host_no, acornscsi_target(host), host->SCpnt->tag); +#endif + /* + * A linked command should only terminate with one of these messages + * if there are more linked commands available. + */ + if (!host->SCpnt->next_link) { + printk (KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", + instance->host_no, acornscsi_target (host), host->SCpnt->tag); + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + } else { + Scsi_Cmnd *SCpnt = host->SCpnt; + + acornscsi_dma_cleanup (host); + + host->SCpnt = host->SCpnt->next_link; + host->SCpnt->tag = SCpnt->tag; + SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status; + SCpnt->done (SCpnt); + + /* initialise host->SCpnt->SCp */ + } + break; + } +#endif + + default: /* reject message */ + printk (KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", + host->host->host_no, acornscsi_target (host), + message[0]); + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + msgqueue_flush (&host->scsi.msgs); + msgqueue_addmsg (&host->scsi.msgs, 1, MESSAGE_REJECT); + host->scsi.phase = PHASE_MSGIN; + break; + } + acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); +} + +/* + * Function: int acornscsi_buildmessages (AS_Host *host) + * Purpose : build the connection messages for a host + * Params : host - host to add messages to + */ +static +void acornscsi_buildmessages (AS_Host *host) +{ +#if 0 + /* does the device need resetting? */ + if (cmd_reset) { + msgqueue_addmsg (&host->scsi.msgs, 1, BUS_DEVICE_RESET); + return; + } +#endif + + msgqueue_addmsg (&host->scsi.msgs, 1, + IDENTIFY(host->device[host->SCpnt->target].disconnect_ok, + host->SCpnt->lun)); + +#if 0 + /* does the device need the current command aborted */ + if (cmd_aborted) { + acornscsi_abortcmd (host->SCpnt->tag); + return; + } +#endif + +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + if (host->SCpnt->tag) { + unsigned int tag_type; + + if (host->SCpnt->cmnd[0] == REQUEST_SENSE || + host->SCpnt->cmnd[0] == TEST_UNIT_READY || + host->SCpnt->cmnd[0] == INQUIRY) + tag_type = HEAD_OF_QUEUE_TAG; + else + tag_type = SIMPLE_QUEUE_TAG; + msgqueue_addmsg (&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); + } +#endif + +#ifdef CONFIG_SCSI_ACORNSCSI_SYNC + if (host->device[host->SCpnt->target].sync_state == SYNC_NEGOCIATE) { + host->device[host->SCpnt->target].sync_state = SYNC_SENT_REQUEST; + msgqueue_addmsg (&host->scsi.msgs, 5, + EXTENDED_MESSAGE, 3, EXTENDED_SDTR, + sdtr_period / 4, sdtr_size); + } +#endif +} + +/* + * Function: int acornscsi_starttransfer (AS_Host *host) + * Purpose : transfer data to/from connected target + * Params : host - host to which target is connected + * Returns : 0 if failure + */ +static +int acornscsi_starttransfer (AS_Host *host) +{ + int residual; + + if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) { + printk (KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", + host->host->host_no, acornscsi_target (host)); + return 0; + } + + residual = host->SCpnt->request_bufflen - host->scsi.SCp.have_data_in; + + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->target].sync_xfer); + sbic_arm_writenext (host->scsi.io_port, residual >> 16); + sbic_arm_writenext (host->scsi.io_port, residual >> 8); + sbic_arm_writenext (host->scsi.io_port, residual); + acornscsi_sbic_issuecmd (host, CMND_XFERINFO); + return 1; +} + +/* ========================================================================================= + * Connection & Disconnection + */ +/* + * Function : acornscsi_reconnect (AS_Host *host) + * Purpose : reconnect a previously disconnected command + * Params : host - host specific data + * Remarks : SCSI spec says: + * 'The set of active pointers is restored from the set + * of saved pointers upon reconnection of the I/O process' + */ +static +int acornscsi_reconnect (AS_Host *host) +{ + unsigned int target, lun, ok = 0; + + target = sbic_arm_read (host->scsi.io_port, SOURCEID); + + if (!(target & 8)) + printk (KERN_ERR "scsi%d: invalid source id after reselection " + "- device fault?\n", + host->host->host_no); + + target &= 7; + + if (host->SCpnt && !host->scsi.disconnectable) { + printk (KERN_ERR "scsi%d.%d: reconnected while command in " + "progress to target %d?\n", + host->host->host_no, target, host->SCpnt->target); + host->SCpnt = NULL; + } + + lun = sbic_arm_read (host->scsi.io_port, DATA) & 7; + + host->scsi.reconnected.target = target; + host->scsi.reconnected.lun = lun; + host->scsi.reconnected.tag = 0; + + if (host->scsi.disconnectable && host->SCpnt && + host->SCpnt->target == target && host->SCpnt->lun == lun) + ok = 1; + + if (!ok && queue_probetgtlun (&host->queues.disconnected, target, lun)) + ok = 1; + + ADD_STATUS(target, 0x81, host->scsi.phase, 0); + + if (ok) { + host->scsi.phase = PHASE_RECONNECTED; + } else { + /* this doesn't seem to work */ + printk (KERN_ERR "scsi%d.%c: reselected with no command " + "to reconnect with\n", + host->host->host_no, '0' + target); + acornscsi_dumplog (host, target); + acornscsi_sbic_issuecmd (host, CMND_ASSERTATN); + msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); + host->scsi.phase = PHASE_ABORTED; + } + acornscsi_sbic_issuecmd (host, CMND_NEGATEACK); + return !ok; +} + +/* + * Function: int acornscsi_reconect_finish (AS_Host *host) + * Purpose : finish reconnecting a command + * Params : host - host to complete + * Returns : 0 if failed + */ +static +int acornscsi_reconnect_finish (AS_Host *host) +{ + if (host->scsi.disconnectable && host->SCpnt) { + host->scsi.disconnectable = 0; + if (host->SCpnt->target == host->scsi.reconnected.target && + host->SCpnt->lun == host->scsi.reconnected.lun && + host->SCpnt->tag == host->scsi.reconnected.tag) { +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + DBG(host->SCpnt, printk ("scsi%d.%c: reconnected", + host->host->host_no, acornscsi_target (host))); +#endif + } else { + queue_add_cmd_tail (&host->queues.disconnected, host->SCpnt); +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + DBG(host->SCpnt, printk ("scsi%d.%c: had to move command " + "to disconnected queue\n", + host->host->host_no, acornscsi_target (host))); +#endif + host->SCpnt = NULL; + } + } + if (!host->SCpnt) { + host->SCpnt = queue_remove_tgtluntag (&host->queues.disconnected, + host->scsi.reconnected.target, + host->scsi.reconnected.lun, + host->scsi.reconnected.tag); +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + DBG(host->SCpnt, printk ("scsi%d.%c: had to get command", + host->host->host_no, acornscsi_target (host))); +#endif + } + + if (!host->SCpnt) { + acornscsi_abortcmd (host, host->scsi.reconnected.tag); + host->scsi.phase = PHASE_ABORTED; + } else { + /* + * Restore data pointer from SAVED pointers. + */ + host->scsi.SCp = host->SCpnt->SCp; +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + printk (", data pointers: [%p, %X]", + host->scsi.SCp.ptr, host->scsi.SCp.this_residual); +#endif + } +#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) + printk ("\n"); +#endif + + host->dma.transferred = host->scsi.SCp.have_data_in; + + return host->SCpnt != NULL; +} + +/* + * Function: void acornscsi_disconnect_unexpected (AS_Host *host) + * Purpose : handle an unexpected disconnect + * Params : host - host on which disconnect occurred + */ +static +void acornscsi_disconnect_unexpected (AS_Host *host) +{ + printk (KERN_ERR "scsi%d.%c: unexpected disconnect\n", + host->host->host_no, acornscsi_target (host)); +#if (DEBUG & DEBUG_ABORT) + acornscsi_dumplog (host, 8); +#endif + + acornscsi_done (host, &host->SCpnt, DID_ABORT); +} + +/* + * Function: void acornscsi_abortcmd (AS_host *host, unsigned char tag) + * Purpose : abort a currently executing command + * Params : host - host with connected command to abort + * tag - tag to abort + */ +static +void acornscsi_abortcmd (AS_Host *host, unsigned char tag) +{ + sbic_arm_write (host->scsi.io_port, CMND, CMND_ASSERTATN); + + msgqueue_flush (&host->scsi.msgs); +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + if (tag) + msgqueue_addmsg (&host->scsi.msgs, 2, ABORT_TAG, tag); + else +#endif + msgqueue_addmsg (&host->scsi.msgs, 1, ABORT); +} + +/* ========================================================================================== + * Interrupt routines. + */ +/* + * Function: int acornscsi_sbicintr (AS_Host *host) + * Purpose : handle interrupts from SCSI device + * Params : host - host to process + * Returns : INTR_PROCESS if expecting another SBIC interrupt + * INTR_IDLE if no interrupt + * INTR_NEXT_COMMAND if we have finished processing the command + */ +static +intr_ret_t acornscsi_sbicintr (AS_Host *host, int in_irq) +{ + unsigned int asr, ssr; + + asr = sbic_arm_read (host->scsi.io_port, ASR); + if (!(asr & ASR_INT)) + return INTR_IDLE; + + ssr = sbic_arm_read (host->scsi.io_port, SSR); + +#if (DEBUG & DEBUG_PHASES) + print_sbic_status(asr, ssr, host->scsi.phase); +#endif + + ADD_STATUS(8, ssr, host->scsi.phase, in_irq); + + if (host->SCpnt && !host->scsi.disconnectable) + ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq); + + switch (ssr) { + case 0x00: /* reset state - not advanced */ + printk (KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", + host->host->host_no); + /* setup sbic - WD33C93A */ + sbic_arm_write (host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id); + sbic_arm_write (host->scsi.io_port, CMND, CMND_RESET); + return INTR_IDLE; + + case 0x01: /* reset state - advanced */ + sbic_arm_write (host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI); + sbic_arm_write (host->scsi.io_port, TIMEOUT, TIMEOUT_TIME); + sbic_arm_write (host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA); + sbic_arm_write (host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP); + msgqueue_flush (&host->scsi.msgs); + return INTR_IDLE; + + case 0x41: /* unexpected disconnect aborted command */ + acornscsi_disconnect_unexpected (host); + return INTR_NEXT_COMMAND; + } + + switch (host->scsi.phase) { + case PHASE_CONNECTING: /* STATE: command removed from issue queue */ + switch (ssr) { + case 0x11: /* -> PHASE_CONNECTED */ + /* BUS FREE -> SELECTION */ + host->scsi.phase = PHASE_CONNECTED; + msgqueue_flush (&host->scsi.msgs); + host->dma.transferred = host->scsi.SCp.have_data_in; + /* 33C93 gives next interrupt indicating bus phase */ + asr = sbic_arm_read (host->scsi.io_port, ASR); + if (!(asr & ASR_INT)) + break; + ssr = sbic_arm_read (host->scsi.io_port, SSR); + ADD_STATUS(8, ssr, host->scsi.phase, 1); + ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, 1); + goto connected; + + case 0x42: /* select timed out */ + /* -> PHASE_IDLE */ + acornscsi_done (host, &host->SCpnt, DID_NO_CONNECT); + return INTR_NEXT_COMMAND; + + case 0x81: /* -> PHASE_RECONNECTED or PHASE_ABORTED */ + /* BUS FREE -> RESELECTION */ + host->origSCpnt = host->SCpnt; + host->SCpnt = NULL; + msgqueue_flush (&host->scsi.msgs); + acornscsi_reconnect (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd (host, host->SCpnt->tag); + } + return INTR_PROCESSING; + + connected: + case PHASE_CONNECTED: /* STATE: device selected ok */ + switch (ssr) { +#ifdef NONSTANDARD + case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ + /* SELECTION -> COMMAND */ + acornscsi_sendcommand (host); + break; + + case 0x8b: /* -> PHASE_STATUS */ + /* SELECTION -> STATUS */ + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; +#endif + + case 0x8e: /* -> PHASE_MSGOUT */ + /* SELECTION ->MESSAGE OUT */ + host->scsi.phase = PHASE_MSGOUT; + acornscsi_buildmessages (host); + acornscsi_sendmessage (host); + break; + + /* these should not happen */ + case 0x85: /* target disconnected */ + acornscsi_done (host, &host->SCpnt, DID_ERROR); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + acornscsi_abortcmd (host, host->SCpnt->tag); + } + return INTR_PROCESSING; + + case PHASE_MSGOUT: /* STATE: connected & sent IDENTIFY message */ + /* + * SCSI standard says th at a MESSAGE OUT phases can be followed by a DATA phase + */ + switch (ssr) { + case 0x8a: + case 0x1a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ + /* MESSAGE OUT -> COMMAND */ + acornscsi_sendcommand (host); + break; + + case 0x1b: /* -> PHASE_STATUS */ + /* MESSAGE OUT -> STATUS */ + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x8e: /* -> PHASE_MSGOUT */ + /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */ + acornscsi_sendmessage (host); + break; + + case 0x4f: + case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + /* MESSAGE OUT -> MESSAGE IN */ + acornscsi_message (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_COMMAND: /* STATE: connected & command sent */ + switch (ssr) { + case 0x18: /* -> PHASE_DATAOUT */ + /* COMMAND -> DATA OUT */ + if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) + acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup (host, DMA_OUT); + if (!acornscsi_starttransfer (host)) + acornscsi_abortcmd (host, host->SCpnt->tag); + host->scsi.phase = PHASE_DATAOUT; + return INTR_IDLE; + + case 0x19: /* -> PHASE_DATAIN */ + /* COMMAND -> DATA IN */ + if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) + acornscsi_abortcmd (host, host->SCpnt->tag); + acornscsi_dma_setup (host, DMA_IN); + if (!acornscsi_starttransfer (host)) + acornscsi_abortcmd (host, host->SCpnt->tag); + host->scsi.phase = PHASE_DATAIN; + return INTR_IDLE; + + case 0x1b: /* -> PHASE_STATUS */ + /* COMMAND -> STATUS */ + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x1e: /* -> PHASE_MSGOUT */ + /* COMMAND -> MESSAGE OUT */ + acornscsi_sendmessage (host); + break; + + case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + /* COMMAND -> MESSAGE IN */ + acornscsi_message (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_DISCONNECT: /* STATE: connected, received DISCONNECT msg */ + if (ssr == 0x85) { /* -> PHASE_IDLE */ + host->scsi.disconnectable = 1; + host->scsi.reconnected.tag = 0; + host->scsi.phase = PHASE_IDLE; + host->stats.disconnects += 1; + } else { + printk (KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_NEXT_COMMAND; + + case PHASE_IDLE: /* STATE: disconnected */ + if (ssr == 0x81) /* -> PHASE_RECONNECTED or PHASE_ABORTED */ + acornscsi_reconnect (host); + else { + printk (KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_RECONNECTED: /* STATE: device reconnected to initiator */ + /* + * Command reconnected - if MESGIN, get message - it may be + * the tag. If not, get command out of disconnected queue + */ + /* + * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY, + * reconnect I_T_L command + */ + if (ssr != 0x8f && !acornscsi_reconnect_finish (host)) + return INTR_IDLE; + ADD_STATUS(host->SCpnt->target, ssr, host->scsi.phase, in_irq); + switch (ssr) { + case 0x88: /* data out phase */ + /* -> PHASE_DATAOUT */ + /* MESSAGE IN -> DATA OUT */ + acornscsi_dma_setup (host, DMA_OUT); + if (!acornscsi_starttransfer (host)) + acornscsi_abortcmd (host, host->SCpnt->tag); + host->scsi.phase = PHASE_DATAOUT; + return INTR_IDLE; + + case 0x89: /* data in phase */ + /* -> PHASE_DATAIN */ + /* MESSAGE IN -> DATA IN */ + acornscsi_dma_setup (host, DMA_IN); + if (!acornscsi_starttransfer (host)) + acornscsi_abortcmd (host, host->SCpnt->tag); + host->scsi.phase = PHASE_DATAIN; + return INTR_IDLE; + + case 0x8a: /* command out */ + /* MESSAGE IN -> COMMAND */ + acornscsi_sendcommand (host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ + break; + + case 0x8b: /* status in */ + /* -> PHASE_STATUSIN */ + /* MESSAGE IN -> STATUS */ + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x8e: /* message out */ + /* -> PHASE_MSGOUT */ + /* MESSAGE IN -> MESSAGE OUT */ + acornscsi_sendmessage (host); + break; + + case 0x8f: /* message in */ + acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_DATAIN: /* STATE: transferred data in */ + /* + * This is simple - if we disconnect then the DMA address & count is + * correct. + */ + switch (ssr) { + case 0x19: /* -> PHASE_DATAIN */ + acornscsi_abortcmd (host, host->SCpnt->tag); + return INTR_IDLE; + + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x1b: /* -> PHASE_STATUSIN */ + /* DATA IN -> STATUS */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x1e: /* -> PHASE_MSGOUT */ + case 0x4e: /* -> PHASE_MSGOUT */ + /* DATA IN -> MESSAGE OUT */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_sendmessage (host); + break; + + case 0x1f: /* message in */ + case 0x4f: /* message in */ + /* DATA IN -> MESSAGE IN */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_DATAOUT: /* STATE: transferred data out */ + /* + * This is more complicated - if we disconnect, the DMA could be 12 + * bytes ahead of us. We need to correct this. + */ + switch (ssr) { + case 0x18: /* -> PHASE_DATAOUT */ + acornscsi_abortcmd (host, host->SCpnt->tag); + return INTR_IDLE; + + case 0x4b: /* -> PHASE_STATUSIN */ + case 0x1b: /* -> PHASE_STATUSIN */ + /* DATA OUT -> STATUS */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_dma_adjust (host); + acornscsi_readstatusbyte (host); + host->scsi.phase = PHASE_STATUSIN; + break; + + case 0x1e: /* -> PHASE_MSGOUT */ + case 0x4e: /* -> PHASE_MSGOUT */ + /* DATA OUT -> MESSAGE OUT */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_dma_adjust (host); + acornscsi_sendmessage (host); + break; + + case 0x1f: /* message in */ + case 0x4f: /* message in */ + /* DATA OUT -> MESSAGE IN */ + host->scsi.SCp.have_data_in = host->SCpnt->request_bufflen - + acornscsi_sbic_xfcount (host); + acornscsi_dma_stop (host); + acornscsi_dma_adjust (host); + acornscsi_message (host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_STATUSIN: /* STATE: status in complete */ + if (ssr == 0x1f) /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + /* STATUS -> MESSAGE IN */ + acornscsi_message (host); + else if (ssr == 0x1e) /* -> PHASE_MSGOUT */ + /* STATUS -> MESSAGE OUT */ + acornscsi_sendmessage (host); + else { + printk (KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_MSGIN: /* STATE: message in */ + switch (ssr) { + case 0x1e: /* -> PHASE_MSGOUT */ + case 0x4e: /* -> PHASE_MSGOUT */ + /* MESSAGE IN -> MESSAGE OUT */ + acornscsi_sendmessage (host); + break; + + case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ + case 0x2f: + case 0x4f: + case 0x8f: + acornscsi_message (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_DONE: /* STATE: received status & message */ + switch (ssr) { + case 0x85: /* -> PHASE_IDLE */ + acornscsi_done (host, &host->SCpnt, DID_OK); + return INTR_NEXT_COMMAND; + + case 0x8e: + acornscsi_sendmessage (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + case PHASE_ABORTED: + switch (ssr) { + case 0x85: + acornscsi_done (host, &host->SCpnt, DID_ABORT); + return INTR_NEXT_COMMAND; + + case 0x1e: + case 0x2e: + case 0x4e: + case 0x8e: + acornscsi_sendmessage (host); + break; + + default: + printk (KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; + + default: + printk (KERN_ERR "scsi%d.%c: unknown driver phase %d\n", + host->host->host_no, acornscsi_target (host), ssr); + acornscsi_dumplog (host, host->SCpnt ? host->SCpnt->target : 8); + } + return INTR_PROCESSING; +} + +/* + * Prototype: void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) + * Purpose : handle interrupts from Acorn SCSI card + * Params : irq - interrupt number + * dev_id - device specific data (AS_Host structure) + * regs - processor registers when interrupt occurred + */ +static +void acornscsi_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + AS_Host *host = (AS_Host *)dev_id; + intr_ret_t ret; + int iostatus; + int in_irq = 0; + + if (host->scsi.interrupt) + printk ("scsi%d: interrupt re-entered\n", host->host->host_no); + host->scsi.interrupt = 1; + + do { + ret = INTR_IDLE; + + iostatus = inb (host->card.io_intr); + + if (iostatus & 2) { + acornscsi_dma_intr (host); + iostatus = inb (host->card.io_intr); + } + + if (iostatus & 8) + ret = acornscsi_sbicintr (host, in_irq); + + /* + * If we have a transfer pending, start it. + * Only start it if the interface has already started transferring + * it's data + */ + if (host->dma.xfer_required) + acornscsi_dma_xfer (host); + + if (ret == INTR_NEXT_COMMAND) + ret = acornscsi_kick (host); + + in_irq = 1; + } while (ret != INTR_IDLE); + + host->scsi.interrupt = 0; +} + +/*============================================================================================= + * Interfaces between interrupt handler and rest of scsi code + */ + +/* + * Function : acornscsi_queuecmd (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) + * Purpose : queues a SCSI command + * Params : cmd - SCSI command + * done - function called on completion, with pointer to command descriptor + * Returns : 0, or < 0 on error. + */ +int acornscsi_queuecmd (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + AS_Host *host = (AS_Host *)SCpnt->host->hostdata; + + if (!done) { + /* there should be some way of rejecting errors like this without panicing... */ + panic ("scsi%d: queuecommand called with NULL done function [cmd=%p]", + SCpnt->host->host_no, SCpnt); + return -EINVAL; + } + +#if (DEBUG & DEBUG_NO_WRITE) + if (acornscsi_cmdtype (SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->target))) { + printk (KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n", + SCpnt->host->host_no, '0' + SCpnt->target); + SCpnt->result = DID_NO_CONNECT << 16; + done (SCpnt); + return 0; + } +#endif + + SCpnt->scsi_done = done; + SCpnt->host_scribble = NULL; + SCpnt->result = 0; + SCpnt->tag = 0; + SCpnt->SCp.phase = (int)acornscsi_datadirection (SCpnt->cmnd[0]); + SCpnt->SCp.sent_command = 0; + SCpnt->SCp.have_data_in = 0; + SCpnt->SCp.Status = 0; + SCpnt->SCp.Message = 0; + + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + } else { + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + } + + host->stats.queues += 1; + + { + unsigned long flags; + + if (!queue_add_cmd_ordered (&host->queues.issue, SCpnt)) { + SCpnt->result = DID_ERROR << 16; + done (SCpnt); + return 0; + } + save_flags_cli (flags); + if (host->scsi.phase == PHASE_IDLE) + acornscsi_kick (host); + restore_flags (flags); + } + return 0; +} + +/* + * Prototype: void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) + * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 + * Params : SCpntp1 - pointer to command to return + * SCpntp2 - pointer to command to check + * result - result to pass back to mid-level done function + * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2. + */ +static inline +void acornscsi_reportstatus (Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result) +{ + Scsi_Cmnd *SCpnt = *SCpntp1; + + if (SCpnt) { + *SCpntp1 = NULL; + + SCpnt->result = result; + SCpnt->scsi_done (SCpnt); + } + + if (SCpnt == *SCpntp2) + *SCpntp2 = NULL; +} + +/* + * Prototype: int acornscsi_abort (Scsi_Cmnd *SCpnt) + * Purpose : abort a command on this host + * Params : SCpnt - command to abort + * Returns : one of SCSI_ABORT_ macros + */ +int acornscsi_abort (Scsi_Cmnd *SCpnt) +{ + AS_Host *host = (AS_Host *) SCpnt->host->hostdata; + int result = SCSI_ABORT_NOT_RUNNING; + + host->stats.aborts += 1; + +#if (DEBUG & DEBUG_ABORT) + { + int asr, ssr; + asr = sbic_arm_read (host->scsi.io_port, ASR); + ssr = sbic_arm_read (host->scsi.io_port, SSR); + + printk (KERN_WARNING "acornscsi_abort: "); + print_sbic_status(asr, ssr, host->scsi.phase); + acornscsi_dumplog (host, SCpnt->target); + } +#endif + + if (queue_removecmd (&host->queues.issue, SCpnt)) { + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done (SCpnt); +#if (DEBUG & DEBUG_ABORT) + printk ("scsi%d: command on issue queue\n", host->host->host_no); +#endif + result = SCSI_ABORT_SUCCESS; + } else if (queue_cmdonqueue (&host->queues.disconnected, SCpnt)) { + printk ("scsi%d: command on disconnected queue\n", host->host->host_no); + result = SCSI_ABORT_SNOOZE; + } else if (host->SCpnt == SCpnt) { + acornscsi_abortcmd (host, host->SCpnt->tag); + printk ("scsi%d: command executing\n", host->host->host_no); + result = SCSI_ABORT_SNOOZE; + } else if (host->origSCpnt == SCpnt) { + host->origSCpnt = NULL; + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done (SCpnt); +#if (DEBUG & DEBUG_ABORT) + printk ("scsi%d: command waiting for execution\n", host->host->host_no); +#endif + result = SCSI_ABORT_SUCCESS; + } + + if (result == SCSI_ABORT_NOT_RUNNING) { + printk ("scsi%d: abort(): command not running\n", host->host->host_no); + acornscsi_dumplog (host, SCpnt->target); +#if (DEBUG & DEBUG_ABORT) + result = SCSI_ABORT_SNOOZE; +#endif + } + return result; +} + +/* + * Prototype: int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * Purpose : reset a command on this host/reset this host + * Params : SCpnt - command causing reset + * result - what type of reset to perform + * Returns : one of SCSI_RESET_ macros + */ +int acornscsi_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + AS_Host *host = (AS_Host *)SCpnt->host->hostdata; + Scsi_Cmnd *SCptr; + + host->stats.resets += 1; + +#if (DEBUG & DEBUG_RESET) + { + int asr, ssr; + + asr = sbic_arm_read (host->scsi.io_port, ASR); + ssr = sbic_arm_read (host->scsi.io_port, SSR); + + printk (KERN_WARNING "acornscsi_reset: "); + print_sbic_status(asr, ssr, host->scsi.phase); + acornscsi_dumplog (host, SCpnt->target); + } +#endif + + acornscsi_dma_stop (host); + + SCptr = host->SCpnt; + + /* + * do hard reset. This resets all devices on this host, and so we + * must set the reset status on all commands. + */ + acornscsi_resetcard (host); + + /* + * report reset on commands current connected/disconnected + */ + acornscsi_reportstatus (&host->SCpnt, &SCptr, DID_RESET); + + while ((SCptr = queue_remove (&host->queues.disconnected)) != NULL) + acornscsi_reportstatus (&SCptr, &SCpnt, DID_RESET); + + if (SCpnt) { + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done (SCpnt); + } +while (1); + return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS; +} + +/*============================================================================================== + * initialisation & miscellaneous support + */ +static struct expansion_card *ecs[MAX_ECARDS]; + +/* + * Prototype: void acornscsi_init (AS_Host *host) + * Purpose : initialise the AS_Host structure for one interface & setup hardware + * Params : host - host to setup + */ +static +void acornscsi_init (AS_Host *host) +{ + memset (&host->stats, 0, sizeof (host->stats)); + queue_initialise (&host->queues.issue); + queue_initialise (&host->queues.disconnected); + msgqueue_initialise (&host->scsi.msgs); + + acornscsi_resetcard (host); +} + +int acornscsi_detect(Scsi_Host_Template * tpnt) +{ + static const card_ids acornscsi_cids[] = { ACORNSCSI_LIST, { 0xffff, 0xffff } }; + int i, count = 0; + struct Scsi_Host *instance; + AS_Host *host; + + tpnt->proc_dir = &proc_scsi_acornscsi; + + for (i = 0; i < MAX_ECARDS; i++) + ecs[i] = NULL; + + ecard_startfind (); + + while(1) { + ecs[count] = ecard_find(0, acornscsi_cids); + if (!ecs[count]) + break; + + if (ecs[count]->irq == 0xff) { + printk ("scsi: WD33C93 does not have IRQ enabled - ignoring\n"); + continue; + } + + ecard_claim(ecs[count]); /* Must claim here - card produces irq on reset */ + + instance = scsi_register (tpnt, sizeof(AS_Host)); + host = (AS_Host *)instance->hostdata; + + instance->io_port = ecard_address (ecs[count], ECARD_MEMC, 0); + instance->irq = ecs[count]->irq; + + host->host = instance; + host->scsi.io_port = ioaddr (instance->io_port + 0x800); + host->scsi.irq = instance->irq; + host->card.io_intr = POD_SPACE(instance->io_port) + 0x800; + host->card.io_page = POD_SPACE(instance->io_port) + 0xc00; + host->card.io_ram = ioaddr (instance->io_port); + host->dma.io_port = instance->io_port + 0xc00; + host->dma.io_intr_clear = POD_SPACE(instance->io_port) + 0x800; + + request_region (instance->io_port + 0x800, 2, "acornscsi(sbic)"); + request_region (host->card.io_intr, 1, "acornscsi(intr)"); + request_region (host->card.io_page, 1, "acornscsi(page)"); +#ifdef USE_DMAC + request_region (host->dma.io_port, 256, "acornscsi(dmac)"); +#endif + request_region (instance->io_port, 2048, "acornscsi(ram)"); + + if (request_irq(host->scsi.irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", host)) { + printk(KERN_CRIT "scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, host->scsi.irq); + host->scsi.irq = NO_IRQ; + } + + acornscsi_init (host); + + ++count; + } + return count; +} + +/* + * Function: int acornscsi_release (struct Scsi_Host *host) + * Purpose : release all resources used by this adapter + * Params : host - driver structure to release + * Returns : nothing of any consequence + */ +int acornscsi_release (struct Scsi_Host *instance) +{ + AS_Host *host = (AS_Host *)instance->hostdata; + int i; + + /* + * Put card into RESET state + */ + outb (0x80, host->card.io_page); + + if (host->scsi.irq != NO_IRQ) + free_irq (host->scsi.irq, host); + + release_region (instance->io_port + 0x800, 2); + release_region (host->card.io_intr, 1); + release_region (host->card.io_page, 1); + release_region (host->dma.io_port, 256); + release_region (instance->io_port, 2048); + + for (i = 0; i < MAX_ECARDS; i++) + if (ecs[i] && instance->io_port == ecard_address (ecs[i], ECARD_MEMC, 0)) + ecard_release (ecs[i]); + + msgqueue_free (&host->scsi.msgs); + queue_free (&host->queues.disconnected); + queue_free (&host->queues.issue); + + return 0; +} + +/* + * Function: char *acornscsi_info (struct Scsi_Host *host) + * Purpose : return a string describing this interface + * Params : host - host to give information on + * Returns : a constant string + */ +const +char *acornscsi_info(struct Scsi_Host *host) +{ + static char string[100], *p; + + p = string; + + p += sprintf (string, "%s at port %X irq %d v%d.%d.%d" +#ifdef CONFIG_SCSI_ACORNSCSI_SYNC + " SYNC" +#endif +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + " TAG" +#endif +#ifdef CONFIG_SCSI_ACORNSCSI_LINK + " LINK" +#endif +#if (DEBUG & DEBUG_NO_WRITE) + " NOWRITE ("NO_WRITE_STR")" +#endif + , host->hostt->name, host->io_port, host->irq, + VER_MAJOR, VER_MINOR, VER_PATCH); + return string; +} + +int acornscsi_proc_info(char *buffer, char **start, off_t offset, + int length, int host_no, int inout) +{ + int pos, begin = 0, devidx; + struct Scsi_Host *instance = scsi_hostlist; + Scsi_Device *scd; + AS_Host *host; + char *p = buffer; + + for (instance = scsi_hostlist; + instance && instance->host_no != host_no; + instance = instance->next); + + if (inout == 1 || !instance) + return -EINVAL; + + host = (AS_Host *)instance->hostdata; + + p += sprintf (p, "AcornSCSI driver v%d.%d.%d" +#ifdef CONFIG_SCSI_ACORNSCSI_SYNC + " SYNC" +#endif +#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE + " TAG" +#endif +#ifdef CONFIG_SCSI_ACORNSCSI_LINK + " LINK" +#endif +#if (DEBUG & DEBUG_NO_WRITE) + " NOWRITE ("NO_WRITE_STR")" +#endif + "\n\n", VER_MAJOR, VER_MINOR, VER_PATCH); + + p += sprintf (p, "SBIC: WD33C93A Address: %08X IRQ : %d\n", + host->scsi.io_port, host->scsi.irq); +#ifdef USE_DMAC + p += sprintf (p, "DMAC: uPC71071 Address: %08X IRQ : %d\n\n", + host->dma.io_port, host->scsi.irq); +#endif + + p += sprintf (p, "Statistics:\n", + "Queued commands: %-10d Issued commands: %-10d\n" + "Done commands : %-10d Reads : %-10d\n" + "Writes : %-10d Others : %-10d\n" + "Disconnects : %-10d Aborts : %-10d\n" + "Resets : %-10d\n\nLast phases:", + host->stats.queues, host->stats.removes, + host->stats.fins, host->stats.reads, + host->stats.writes, host->stats.miscs, + host->stats.disconnects, host->stats.aborts, + host->stats.resets); + + for (devidx = 0; devidx < 9; devidx ++) { + unsigned int statptr, prev; + + p += sprintf (p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx)); + statptr = status_ptr[devidx] - 10; + + if ((signed int)statptr < 0) + statptr += 16; + + prev = status[devidx][statptr].when; + + for (; statptr != status_ptr[devidx]; statptr = (statptr + 1) & 15) { + if (status[devidx][statptr].when) { + p += sprintf (p, "%c%02X:%02X+%2ld", + status[devidx][statptr].irq ? '-' : ' ', + status[devidx][statptr].ph, + status[devidx][statptr].ssr, + (status[devidx][statptr].when - prev) < 100 ? + (status[devidx][statptr].when - prev) : 99); + prev = status[devidx][statptr].when; + } + } + } + + p += sprintf (p, "\nAttached devices:%s\n", instance->host_queue ? "" : " none"); + + for (scd = instance->host_queue; scd; scd = scd->next) { + int len; + + proc_print_scsidevice (scd, p, &len, 0); + p += len; + + p += sprintf (p, "Extensions: "); + + if (scd->tagged_supported) + p += sprintf (p, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", scd->current_tag); + p += sprintf (p, "\nTransfers: "); + if (host->device[scd->id].sync_xfer & 15) + p += sprintf (p, "sync, offset %d, %d ns\n", + host->device[scd->id].sync_xfer & 15, + acornscsi_getperiod (host->device[scd->id].sync_xfer)); + else + p += sprintf (p, "async\n"); + + pos = p - buffer; + if (pos + begin < offset) { + begin += pos; + p = buffer; + } + pos = p - buffer; + if (pos + begin > offset + length) + break; + } + + pos = p - buffer; + + *start = buffer + (offset - begin); + pos -= offset - begin; + + if (pos > length) + pos = length; + + return pos; +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = ACORNSCSI_3; + +#include "../../scsi/scsi_module.c" +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/acornscsi.h new/linux/drivers/acorn/scsi/acornscsi.h --- old/linux/drivers/acorn/scsi/acornscsi.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/acornscsi.h Sun Dec 28 18:06:25 1997 @@ -0,0 +1,378 @@ +#ifndef ACORNSCSI_H +#define ACORNSCSI_H + +#ifndef ASM +extern int acornscsi_detect (Scsi_Host_Template *); +extern int acornscsi_release (struct Scsi_Host *); +extern const char *acornscsi_info (struct Scsi_Host *); +extern int acornscsi_queuecmd (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int acornscsi_abort (Scsi_Cmnd *); +extern int acornscsi_reset (Scsi_Cmnd *, unsigned int); +extern int acornscsi_proc_info (char *, char **, off_t, int, int, int); +extern int acornscsi_biosparam (Disk *, kdev_t, int []); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#ifndef PROC_SCSI_AKA30 +#include "linux/proc_fs.h" +#define PROC_SCSI_AKA30 PROC_SCSI_EATA +#endif + +#include + +#define ACORNSCSI_3 { \ +proc_info: acornscsi_proc_info, \ +name: "AcornSCSI", \ +detect: acornscsi_detect, \ +release: acornscsi_release, /* Release */ \ +info: acornscsi_info, \ +queuecommand: acornscsi_queuecmd, \ +abort: acornscsi_abort, \ +reset: acornscsi_reset, \ +bios_param: scsicam_bios_param, \ +can_queue: CAN_QUEUE, /* can_queue */ \ +this_id: 7, /* this id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CMD_PER_LUN, /* cmd_per_lun */ \ +unchecked_isa_dma: 0, /* unchecked isa dma */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +/* SBIC registers */ +#define OWNID 0 +#define OWNID_FS1 (1<<7) +#define OWNID_FS2 (1<<6) +#define OWNID_EHP (1<<4) +#define OWNID_EAF (1<<3) + +#define CTRL 1 +#define CTRL_DMAMODE (1<<7) +#define CTRL_DMADBAMODE (1<<6) +#define CTRL_DMABURST (1<<5) +#define CTRL_DMAPOLLED 0 +#define CTRL_HHP (1<<4) +#define CTRL_EDI (1<<3) +#define CTRL_IDI (1<<2) +#define CTRL_HA (1<<1) +#define CTRL_HSP (1<<0) + +#define TIMEOUT 2 +#define TOTSECTS 3 +#define TOTHEADS 4 +#define TOTCYLH 5 +#define TOTCYLL 6 +#define LOGADDRH 7 +#define LOGADDRM2 8 +#define LOGADDRM1 9 +#define LOGADDRL 10 +#define SECTORNUM 11 +#define HEADNUM 12 +#define CYLH 13 +#define CYLL 14 +#define TARGETLUN 15 +#define TARGETLUN_TLV (1<<7) +#define TARGETLUN_DOK (1<<6) + +#define CMNDPHASE 16 +#define SYNCHTRANSFER 17 +#define SYNCHTRANSFER_OF0 0x00 +#define SYNCHTRANSFER_OF1 0x01 +#define SYNCHTRANSFER_OF2 0x02 +#define SYNCHTRANSFER_OF3 0x03 +#define SYNCHTRANSFER_OF4 0x04 +#define SYNCHTRANSFER_OF5 0x05 +#define SYNCHTRANSFER_OF6 0x06 +#define SYNCHTRANSFER_OF7 0x07 +#define SYNCHTRANSFER_OF8 0x08 +#define SYNCHTRANSFER_OF9 0x09 +#define SYNCHTRANSFER_OF10 0x0A +#define SYNCHTRANSFER_OF11 0x0B +#define SYNCHTRANSFER_OF12 0x0C +#define SYNCHTRANSFER_8DBA 0x00 +#define SYNCHTRANSFER_2DBA 0x20 +#define SYNCHTRANSFER_3DBA 0x30 +#define SYNCHTRANSFER_4DBA 0x40 +#define SYNCHTRANSFER_5DBA 0x50 +#define SYNCHTRANSFER_6DBA 0x60 +#define SYNCHTRANSFER_7DBA 0x70 + +#define TRANSCNTH 18 +#define TRANSCNTM 19 +#define TRANSCNTL 20 +#define DESTID 21 +#define DESTID_SCC (1<<7) +#define DESTID_DPD (1<<6) + +#define SOURCEID 22 +#define SOURCEID_ER (1<<7) +#define SOURCEID_ES (1<<6) +#define SOURCEID_DSP (1<<5) +#define SOURCEID_SIV (1<<4) + +#define SSR 23 +#define CMND 24 +#define CMND_RESET 0x00 +#define CMND_ABORT 0x01 +#define CMND_ASSERTATN 0x02 +#define CMND_NEGATEACK 0x03 +#define CMND_DISCONNECT 0x04 +#define CMND_RESELECT 0x05 +#define CMND_SELWITHATN 0x06 +#define CMND_SELECT 0x07 +#define CMND_SELECTATNTRANSFER 0x08 +#define CMND_SELECTTRANSFER 0x09 +#define CMND_RESELECTRXDATA 0x0A +#define CMND_RESELECTTXDATA 0x0B +#define CMND_WAITFORSELRECV 0x0C +#define CMND_SENDSTATCMD 0x0D +#define CMND_SENDDISCONNECT 0x0E +#define CMND_SETIDI 0x0F +#define CMND_RECEIVECMD 0x10 +#define CMND_RECEIVEDTA 0x11 +#define CMND_RECEIVEMSG 0x12 +#define CMND_RECEIVEUSP 0x13 +#define CMND_SENDCMD 0x14 +#define CMND_SENDDATA 0x15 +#define CMND_SENDMSG 0x16 +#define CMND_SENDUSP 0x17 +#define CMND_TRANSLATEADDR 0x18 +#define CMND_XFERINFO 0x20 +#define CMND_SBT (1<<7) + +#define DATA 25 +#define ASR 26 +#define ASR_INT (1<<7) +#define ASR_LCI (1<<6) +#define ASR_BSY (1<<5) +#define ASR_CIP (1<<4) +#define ASR_PE (1<<1) +#define ASR_DBR (1<<0) + +/* DMAC registers */ +#define INIT 0x00 +#define INIT_8BIT (1) + +#define CHANNEL 0x80 +#define CHANNEL_0 0x00 +#define CHANNEL_1 0x01 +#define CHANNEL_2 0x02 +#define CHANNEL_3 0x03 + +#define TXCNTLO 0x01 +#define TXCNTHI 0x81 +#define TXADRLO 0x02 +#define TXADRMD 0x82 +#define TXADRHI 0x03 + +#define DEVCON0 0x04 +#define DEVCON0_AKL (1<<7) +#define DEVCON0_RQL (1<<6) +#define DEVCON0_EXW (1<<5) +#define DEVCON0_ROT (1<<4) +#define DEVCON0_CMP (1<<3) +#define DEVCON0_DDMA (1<<2) +#define DEVCON0_AHLD (1<<1) +#define DEVCON0_MTM (1<<0) + +#define DEVCON1 0x84 +#define DEVCON1_WEV (1<<1) +#define DEVCON1_BHLD (1<<0) + +#define MODECON 0x05 +#define MODECON_WOED 0x01 +#define MODECON_VERIFY 0x00 +#define MODECON_READ 0x04 +#define MODECON_WRITE 0x08 +#define MODECON_AUTOINIT 0x10 +#define MODECON_ADDRDIR 0x20 +#define MODECON_DEMAND 0x00 +#define MODECON_SINGLE 0x40 +#define MODECON_BLOCK 0x80 +#define MODECON_CASCADE 0xC0 + +#define STATUS 0x85 +#define STATUS_TC0 (1<<0) +#define STATUS_RQ0 (1<<4) + +#define TEMPLO 0x06 +#define TEMPHI 0x86 +#define REQREG 0x07 +#define MASKREG 0x87 +#define MASKREG_M0 0x01 +#define MASKREG_M1 0x02 +#define MASKREG_M2 0x04 +#define MASKREG_M3 0x08 + +/* miscellaneous internal variables */ + +#define POD_SPACE(x) ((x) + 0xd0000) +#define MASK_ON (MASKREG_M3|MASKREG_M2|MASKREG_M1|MASKREG_M0) +#define MASK_OFF (MASKREG_M3|MASKREG_M2|MASKREG_M1) + +#define min(x,y) ((x) < (y) ? (x) : (y)) +#define max(x,y) ((x) < (y) ? (y) : (x)) + +/* + * SCSI driver phases + */ +typedef enum { + PHASE_IDLE, /* we're not planning on doing anything */ + PHASE_CONNECTING, /* connecting to a target */ + PHASE_CONNECTED, /* connected to a target */ + PHASE_MSGOUT, /* message out to device */ + PHASE_RECONNECTED, /* reconnected */ + PHASE_COMMANDPAUSED, /* command partly sent */ + PHASE_COMMAND, /* command all sent */ + PHASE_DATAOUT, /* data out to device */ + PHASE_DATAIN, /* data in from device */ + PHASE_STATUSIN, /* status in from device */ + PHASE_MSGIN, /* message in from device */ + PHASE_DONE, /* finished */ + PHASE_ABORTED, /* aborted */ + PHASE_DISCONNECT, /* disconnecting */ +} phase_t; + +/* + * After interrupt, what to do now + */ +typedef enum { + INTR_IDLE, /* not expecting another IRQ */ + INTR_NEXT_COMMAND, /* start next command */ + INTR_PROCESSING, /* interrupt routine still processing */ +} intr_ret_t; + +/* + * DMA direction + */ +typedef enum { + DMA_OUT, /* DMA from memory to chip */ + DMA_IN /* DMA from chip to memory */ +} dmadir_t; + +/* + * Synchronous transfer state + */ +typedef enum { /* Synchronous transfer state */ + SYNC_ASYNCHRONOUS, /* don't negociate synchronous transfers*/ + SYNC_NEGOCIATE, /* start negociation */ + SYNC_SENT_REQUEST, /* sent SDTR message */ + SYNC_COMPLETED, /* received SDTR reply */ +} syncxfer_t; + +/* + * Command type + */ +typedef enum { /* command type */ + CMD_READ, /* READ_6, READ_10, READ_12 */ + CMD_WRITE, /* WRITE_6, WRITE_10, WRITE_12 */ + CMD_MISC, /* Others */ +} cmdtype_t; + +/* + * Data phase direction + */ +typedef enum { /* Data direction */ + DATADIR_IN, /* Data in phase expected */ + DATADIR_OUT /* Data out phase expected */ +} datadir_t; + +#include "queue.h" +#include "msgqueue.h" + +/* + * AcornSCSI host specific data + */ +typedef struct acornscsi_hostdata { + /* miscellaneous */ + struct Scsi_Host *host; /* host */ + Scsi_Cmnd *SCpnt; /* currently processing command */ + Scsi_Cmnd *origSCpnt; /* original connecting command */ + + /* driver information */ + struct { + unsigned int io_port; /* base address of WD33C93 */ + unsigned char irq; /* interrupt */ + phase_t phase; /* current phase */ + + struct { + unsigned char target; /* reconnected target */ + unsigned char lun; /* reconnected lun */ + unsigned char tag; /* reconnected tag */ + } reconnected; + + Scsi_Pointer SCp; /* current commands data pointer */ + + MsgQueue_t msgs; + + unsigned short last_message; /* last message to be sent */ + unsigned char disconnectable:1; /* this command can be disconnected */ + unsigned char interrupt:1; /* interrupt active */ + } scsi; + + /* statistics information */ + struct { + unsigned int queues; + unsigned int removes; + unsigned int fins; + unsigned int reads; + unsigned int writes; + unsigned int miscs; + unsigned int disconnects; + unsigned int aborts; + unsigned int resets; + } stats; + + /* queue handling */ + struct { + Queue_t issue; /* issue queue */ + Queue_t disconnected; /* disconnected command queue */ + } queues; + + /* per-device info */ + struct { + unsigned char sync_xfer; /* synchronous transfer (SBIC value) */ + syncxfer_t sync_state; /* sync xfer negociation state */ + unsigned char disconnect_ok:1; /* device can disconnect */ + } device[8]; + unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ + + /* DMA info */ + struct { + unsigned int io_port; /* base address of DMA controller */ + unsigned int io_intr_clear; /* address of DMA interrupt clear */ + unsigned int free_addr; /* next free address */ + unsigned int start_addr; /* start address of current transfer */ + dmadir_t direction; /* dma direction */ + unsigned int transferred; /* number of bytes transferred */ + unsigned int xfer_start; /* scheduled DMA transfer start */ + unsigned int xfer_length; /* scheduled DMA transfer length */ + char *xfer_ptr; /* pointer to area */ + unsigned char xfer_required:1; /* set if we need to transfer something */ + unsigned char xfer_setup:1; /* set if DMA is setup */ + } dma; + + /* card info */ + struct { + unsigned int io_intr; /* base address of interrupt id reg */ + unsigned int io_page; /* base address of page reg */ + unsigned int io_ram; /* base address of RAM access */ + unsigned char page_reg; /* current setting of page reg */ + } card; +} AS_Host; + +#endif /* ndef HOSTS_C */ + +#endif /* ndef ASM */ +#endif /* ACORNSCSI_H */ diff -ur --new-file old/linux/drivers/acorn/scsi/cumana_1.c new/linux/drivers/acorn/scsi/cumana_1.c --- old/linux/drivers/acorn/scsi/cumana_1.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/cumana_1.c Sat Feb 21 22:25:15 1998 @@ -0,0 +1,360 @@ +#define AUTOSENSE +#define PSEUDO_DMA + +/* + * Generic Generic NCR5380 driver + * + * Copyright 1995, Russell King + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + + +/* + * Options : + * + * PARITY - enable parity checking. Not supported. + * + * SCSI2 - enable support for SCSI-II tagged queueing. Untested. + * + * USLEEP - enable support for devices that don't disconnect. Untested. + */ + +/* + * $Log: cumana_NCR5380.c,v $ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "cumana_1.h" +#include "../../scsi/NCR5380.h" +#include "../../scsi/constants.h" + +static const card_ids cumanascsi_cids[] = { + { MANU_CUMANA, PROD_CUMANA_SCSI_1 }, + { 0xffff, 0xffff } +}; + +static struct proc_dir_entry proc_scsi_cumana1 = { + PROC_SCSI_T128, 12, "CumanaSCSI-1", S_IFDIR | S_IRUGO, S_IXUGO, 2 +}; + +/* + * Function : cumanascsi_setup(char *str, int *ints) + * + * Purpose : LILO command line initialization of the overrides array, + * + * Inputs : str - unused, ints - array of integer parameters with ints[0] + * equal to the number of ints. + * + */ + +void cumanascsi_setup(char *str, int *ints) { +} + +#define CUMANA_ADDRESS(card) (ecard_address((card), ECARD_IOC, ECARD_SLOW) + 0x800) +#define CUMANA_IRQ(card) ((card)->irq) +/* + * Function : int cumanascsi_detect(Scsi_Host_Template * tpnt) + * + * Purpose : initializes cumana NCR5380 driver based on the + * command line / compile time port and irq definitions. + * + * Inputs : tpnt - template for this SCSI adapter. + * + * Returns : 1 if a host adapter was found, 0 if not. + * + */ +static struct expansion_card *ecs[4]; + +int cumanascsi_detect(Scsi_Host_Template * tpnt) +{ + int count = 0; + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_cumana1; + + memset (ecs, 0, sizeof (ecs)); + + while(1) { + if((ecs[count] = ecard_find(0, cumanascsi_cids)) == NULL) + break; + + instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); + instance->io_port = CUMANA_ADDRESS(ecs[count]); + instance->irq = CUMANA_IRQ(ecs[count]); + + NCR5380_init(instance, 0); + ecard_claim(ecs[count]); + + instance->n_io_port = 255; + request_region (instance->io_port, instance->n_io_port, "CumanaSCSI-1"); + + ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; + outb(0x00, instance->io_port - 577); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) { + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq == IRQ_NONE) { + printk("scsi%d: interrupts not enabled. for better interactive performance,\n", instance->host_no); + printk("scsi%d: please jumper the board for a free IRQ.\n", instance->host_no); + } + + printk("scsi%d: at port %X irq", instance->host_no, instance->io_port); + if (instance->irq == IRQ_NONE) + printk ("s disabled"); + else + printk (" %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", + CAN_QUEUE, CMD_PER_LUN, CUMANASCSI_PUBLIC_RELEASE); + printk("\nscsi%d:", instance->host_no); + NCR5380_print_options(instance); + printk("\n"); + + ++count; + } + return count; +} + +int cumanascsi_release (struct Scsi_Host *shpnt) +{ + int i; + + if (shpnt->irq != IRQ_NONE) + free_irq (shpnt->irq, NULL); + if (shpnt->io_port) + release_region (shpnt->io_port, shpnt->n_io_port); + + for (i = 0; i < 4; i++) + if (shpnt->io_port == CUMANA_ADDRESS(ecs[i])) + ecard_release (ecs[i]); + return 0; +} + +const char * cumanascsi_info (struct Scsi_Host *spnt) { + return ""; +} + +#ifdef NOT_EFFICIENT +#define CTRL(p,v) outb(*ctrl = (v), (p) - 577) +#define STAT(p) inb((p)+1) +#define IN(p) inb((p)) +#define OUT(v,p) outb((v), (p)) +#else +#define CTRL(p,v) (p[-2308] = (*ctrl = (v))) +#define STAT(p) (p[4]) +#define IN(p) (*(p)) +#define IN2(p) ((unsigned short)(*(volatile unsigned long *)(p))) +#define OUT(v,p) (*(p) = (v)) +#define OUT2(v,p) (*((volatile unsigned long *)(p)) = (v)) +#endif +#define L(v) (((v)<<16)|((v) & 0x0000ffff)) +#define H(v) (((v)>>16)|((v) & 0xffff0000)) + +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; + int oldctrl = *ctrl; + unsigned long *laddr; +#ifdef NOT_EFFICIENT + int iobase = instance->io_port; + int dma_io = iobase & ~(0x3C0000>>2); +#else + volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port); + volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000); +#endif + + if(!len) return 0; + + CTRL(iobase, 0x02); + laddr = (unsigned long *)addr; + while(len >= 32) + { + int status; + unsigned long v; + status = STAT(iobase); + if(status & 0x80) + goto end; + if(!(status & 0x40)) + continue; + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io); + len -= 32; + if(len == 0) + break; + } + + addr = (unsigned char *)laddr; + CTRL(iobase, 0x12); + while(len > 0) + { + int status; + status = STAT(iobase); + if(status & 0x80) + goto end; + if(status & 0x40) + { + OUT(*addr++, dma_io); + if(--len == 0) + break; + } + + status = STAT(iobase); + if(status & 0x80) + goto end; + if(status & 0x40) + { + OUT(*addr++, dma_io); + if(--len == 0) + break; + } + } +end: + CTRL(iobase, oldctrl|0x40); + return len; +} + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; + int oldctrl = *ctrl; + unsigned long *laddr; +#ifdef NOT_EFFICIENT + int iobase = instance->io_port; + int dma_io = iobase & ~(0x3C0000>>2); +#else + volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port); + volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000); +#endif + + if(!len) return 0; + + CTRL(iobase, 0x00); + laddr = (unsigned long *)addr; + while(len >= 32) + { + int status; + status = STAT(iobase); + if(status & 0x80) + goto end; + if(!(status & 0x40)) + continue; + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16); + len -= 32; + if(len == 0) + break; + } + + addr = (unsigned char *)laddr; + CTRL(iobase, 0x10); + while(len > 0) + { + int status; + status = STAT(iobase); + if(status & 0x80) + goto end; + if(status & 0x40) + { + *addr++ = IN(dma_io); + if(--len == 0) + break; + } + + status = STAT(iobase); + if(status & 0x80) + goto end; + if(status & 0x40) + { + *addr++ = IN(dma_io); + if(--len == 0) + break; + } + } +end: + CTRL(iobase, oldctrl|0x40); + return len; +} + +#undef STAT +#undef CTRL +#undef IN +#undef OUT + +#define CTRL(p,v) outb(*ctrl = (v), (p) - 577) + +static char cumanascsi_read(struct Scsi_Host *instance, int reg) +{ + int iobase = instance->io_port; + int i; + int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; + + CTRL(iobase, 0); + i = inb(iobase + 64 + reg); + CTRL(iobase, 0x40); + + return i; +} + +static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value) +{ + int iobase = instance->io_port; + int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; + + CTRL(iobase, 0); + outb(value, iobase + 64 + reg); + CTRL(iobase, 0x40); +} + +#undef CTRL + +#include "../../scsi/NCR5380.c" + +#ifdef MODULE + +Scsi_Host_Template driver_template = CUMANA_NCR5380; + +#include "../../scsi/scsi_module.c" +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/cumana_1.h new/linux/drivers/acorn/scsi/cumana_1.h --- old/linux/drivers/acorn/scsi/cumana_1.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/cumana_1.h Sun Dec 28 18:15:22 1997 @@ -0,0 +1,102 @@ +/* + * Cumana Generic NCR5380 driver defines + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 440-4894 + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * $Log: cumana_NCR5380.h,v $ + */ + +#ifndef CUMANA_NCR5380_H +#define CUMANA_NCR5380_H + +#define CUMANASCSI_PUBLIC_RELEASE 1 + + +#ifndef ASM +int cumanascsi_abort (Scsi_Cmnd *); +int cumanascsi_detect (Scsi_Host_Template *); +int cumanascsi_release (struct Scsi_Host *); +const char *cumanascsi_info (struct Scsi_Host *); +int cumanascsi_reset(Scsi_Cmnd *, unsigned int); +int cumanascsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int cumanascsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#include + +#define CUMANA_NCR5380 { \ +name: "Cumana 16-bit SCSI", \ +detect: cumanascsi_detect, \ +release: cumanascsi_release, /* Release */ \ +info: cumanascsi_info, \ +queuecommand: cumanascsi_queue_command, \ +abort: cumanascsi_abort, \ +reset: cumanascsi_reset, \ +bios_param: scsicam_bios_param, /* biosparam */ \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: 7, /* id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ +unchecked_isa_dma: 0, /* unchecked_isa_dma */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +#define NCR5380_implementation_fields \ + int port, ctrl + +#define NCR5380_local_declare() \ + struct Scsi_Host *_instance + +#define NCR5380_setup(instance) \ + _instance = instance + +#define NCR5380_read(reg) cumanascsi_read(_instance, reg) +#define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value) + +#define NCR5380_intr cumanascsi_intr +#define NCR5380_queue_command cumanascsi_queue_command +#define NCR5380_abort cumanascsi_abort +#define NCR5380_reset cumanascsi_reset +#define NCR5380_proc_info cumanascsi_proc_info + +#define BOARD_NORMAL 0 +#define BOARD_NCR53C400 1 + +#endif /* ndef HOSTS_C */ +#endif /* ndef ASM */ +#endif /* CUMANA_NCR5380_H */ + diff -ur --new-file old/linux/drivers/acorn/scsi/cumana_2.c new/linux/drivers/acorn/scsi/cumana_2.c --- old/linux/drivers/acorn/scsi/cumana_2.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/cumana_2.c Sun Feb 15 17:58:11 1998 @@ -0,0 +1,378 @@ +/* + * linux/arch/arm/drivers/scsi/cumana_2.c + * + * Copyright (C) 1997,1998 Russell King + * + * This driver is based on experimentation. Hence, it may have made + * assumptions about the particular card that I have available, and + * may not be reliable! + * + * Changelog: + * 30-08-1997 RMK 0.0.0 Created, READONLY version + * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../../scsi/sd.h" +#include "../../scsi/hosts.h" +#include "cumana_2.h" +#include "fas216.h" + +/* Hmm - this should go somewhere else */ +#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) + +/* Configuration */ +#define XTALFREQ 40 +#define INT_POLARITY CTRL_INT_HIGH + +/* + * List of devices that the driver will recognise + */ +#define CUMANASCSI2_LIST { MANU_CUMANA, PROD_CUMANA_SCSI_2 } + +/* + * Version + */ +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_PATCH 1 + +static struct expansion_card *ecs[MAX_ECARDS]; + +static struct proc_dir_entry proc_scsi_cumanascsi_2 = { + PROC_SCSI_QLOGICFAS, 6, "cumanascs2", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +/* + * Function: void cumanascsi_2_intr (int irq, void *dev_id, struct pt_regs *regs) + * Purpose : handle interrupts from Cumana SCSI 2 card + * Params : irq - interrupt number + * dev_id - user-defined (Scsi_Host structure) + * regs - processor registers at interrupt + */ +static void cumanascsi_2_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + struct Scsi_Host *instance = (struct Scsi_Host *)dev_id; + + fas216_intr (instance); +} + +/* + * Function: int cumanascsi_2_dma_setup (instance, SCpnt, direction) + * Purpose : initialises DMA/PIO + * Params : instance - host + * SCpnt - command + * direction - DMA on to/off of card + * Returns : 0 if we should not set CMD_WITHDMA for transfer info command + */ +static fasdmatype_t cumanascsi_2_dma_setup (struct Scsi_Host *instance, Scsi_Pointer *SCp, fasdmadir_t direction) +{ + /* + * We don't do DMA + */ + return fasdma_pseudo; +} + +/* + * Function: int cumanascsi_2_dma_pseudo (instance, SCpnt, direction, transfer) + * Purpose : handles pseudo DMA + * Params : instance - host + * SCpnt - command + * direction - DMA on to/off of card + * transfer - minimum number of bytes we expect to transfer + * Returns : bytes transfered + */ +static int +cumanascsi_2_dma_pseudo (struct Scsi_Host *instance, Scsi_Pointer *SCp, + fasdmadir_t direction, int transfer) +{ + CumanaScsi2_Info *info = (CumanaScsi2_Info *)instance->hostdata; + unsigned int length; + unsigned char *addr; + + length = SCp->this_residual; + addr = SCp->ptr; + + if (direction == DMA_OUT) +#if 0 + while (length > 1) { + unsigned long word; + + + if (inb (REG0_STATUS(&info->info)) & STATUS_INT) + goto end; + + if (!(inb (info->cstatus) & CSTATUS_DRQ)) + continue; + + word = *addr | (*addr + 1) << 8; + outw (info->dmaarea); + addr += 2; + length -= 2; + } +#else + printk ("PSEUDO_OUT???\n"); +#endif + else { + if (transfer && (transfer & 255)) { + while (length >= 256) { + if (inb (REG0_STATUS(&info->info)) & STATUS_INT) + goto end; + + if (!(inb (info->cstatus) & CSTATUS_DRQ)) + continue; + + insw (info->dmaarea, addr, 256 >> 1); + addr += 256; + length -= 256; + } + } + + while (length > 0) { + unsigned long word; + + if (inb (REG0_STATUS(&info->info)) & STATUS_INT) + goto end; + + if (!(inb (info->cstatus) & CSTATUS_DRQ)) + continue; + + word = inw (info->dmaarea); + *addr++ = word; + if (--length > 0) { + *addr++ = word >> 8; + length --; + } + } + } + +end: + return SCp->this_residual - length; +} + +/* + * Function: int cumanascsi_2_dma_stop (instance, SCpnt) + * Purpose : stops DMA/PIO + * Params : instance - host + * SCpnt - command + */ +static void cumanascsi_2_dma_stop (struct Scsi_Host *instance, Scsi_Pointer *SCp) +{ + /* + * no DMA to stop + */ +} + +/* + * Function: int cumanascsi_2_detect (Scsi_Host_Template * tpnt) + * Purpose : initialises Cumana SCSI 2 driver + * Params : tpnt - template for this SCSI adapter + * Returns : >0 if host found, 0 otherwise. + */ +int cumanascsi_2_detect (Scsi_Host_Template *tpnt) +{ + static const card_ids cumanascsi_2_cids[] = { CUMANASCSI2_LIST, { 0xffff, 0xffff} }; + int count = 0; + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_cumanascsi_2; + memset (ecs, 0, sizeof (ecs)); + + ecard_startfind (); + + while (1) { + CumanaScsi2_Info *info; + + ecs[count] = ecard_find (0, cumanascsi_2_cids); + if (!ecs[count]) + break; + + ecard_claim (ecs[count]); + + instance = scsi_register (tpnt, sizeof (CumanaScsi2_Info)); + if (!instance) { + ecard_release (ecs[count]); + break; + } + + instance->io_port = ecard_address (ecs[count], ECARD_MEMC, 0); + instance->irq = ecs[count]->irq; + + ecs[count]->irqaddr = (unsigned char *)BUS_ADDR(instance->io_port); + ecs[count]->irqmask = CSTATUS_IRQ; + + request_region (instance->io_port , 1, "cumanascsi2-stat"); + request_region (instance->io_port + 128, 64, "cumanascsi2-dma"); + request_region (instance->io_port + 192, 16, "cumanascsi2-fas"); + if (request_irq (instance->irq, cumanascsi_2_intr, SA_INTERRUPT, "cumanascsi2", instance)) { + printk ("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + } + + info = (CumanaScsi2_Info *)instance->hostdata; + info->info.scsi.io_port = instance->io_port + 192; + info->info.scsi.irq = instance->irq; + info->info.ifcfg.clockrate = XTALFREQ; + info->info.ifcfg.select_timeout = 255; + info->info.dma.setup = cumanascsi_2_dma_setup; + info->info.dma.pseudo = cumanascsi_2_dma_pseudo; + info->info.dma.stop = cumanascsi_2_dma_stop; + info->dmaarea = instance->io_port + 128; + info->cstatus = instance->io_port; + + fas216_init (instance); + ++count; + } + return count; +} + +/* + * Function: int cumanascsi_2_release (struct Scsi_Host * host) + * Purpose : releases all resources used by this adapter + * Params : host - driver host structure to return info for. + * Returns : nothing + */ +int cumanascsi_2_release (struct Scsi_Host *instance) +{ + int i; + + fas216_release (instance); + + if (instance->irq != 255) + free_irq (instance->irq, instance); + release_region (instance->io_port, 1); + release_region (instance->io_port + 128, 32); + release_region (instance->io_port + 192, 16); + + for (i = 0; i < MAX_ECARDS; i++) + if (ecs[i] && instance->io_port == ecard_address (ecs[i], ECARD_MEMC, 0)) + ecard_release (ecs[i]); + return 0; +} + +/* + * Function: const char *cumanascsi_2_info (struct Scsi_Host * host) + * Purpose : returns a descriptive string about this interface, + * Params : host - driver host structure to return info for. + * Returns : pointer to a static buffer containing null terminated string. + */ +const char *cumanascsi_2_info (struct Scsi_Host *host) +{ + CumanaScsi2_Info *info = (CumanaScsi2_Info *)host->hostdata; + static char string[100], *p; + + p = string; + p += sprintf (string, "%s at port %X irq %d v%d.%d.%d scsi %s", + host->hostt->name, host->io_port, host->irq, + VER_MAJOR, VER_MINOR, VER_PATCH, + info->info.scsi.type); + + return string; +} + +/* + * Function: int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset, + * int length, int host_no, int inout) + * Purpose : Return information about the driver to a user process accessing + * the /proc filesystem. + * Params : buffer - a buffer to write information to + * start - a pointer into this buffer set by this routine to the start + * of the required information. + * offset - offset into information that we have read upto. + * length - length of buffer + * host_no - host number to return information for + * inout - 0 for reading, 1 for writing. + * Returns : length of data written to buffer. + */ +int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset, + int length, int host_no, int inout) +{ + int pos, begin; + struct Scsi_Host *host = scsi_hostlist; + CumanaScsi2_Info *info; + Scsi_Device *scd; + + while (host) { + if (host->host_no == host_no) + break; + host = host->next; + } + if (!host) + return 0; + + info = (CumanaScsi2_Info *)host->hostdata; + if (inout == 1) + return -EINVAL; + + begin = 0; + pos = sprintf (buffer, + "Cumana SCSI II driver version %d.%d.%d\n", + VER_MAJOR, VER_MINOR, VER_PATCH); + pos += sprintf (buffer + pos, + "Address: %08X IRQ : %d\n" + "FAS : %s\n\n" + "Statistics:\n", + host->io_port, host->irq, info->info.scsi.type); + + pos += sprintf (buffer+pos, + "Queued commands: %-10ld Issued commands: %-10ld\n" + "Done commands : %-10ld Reads : %-10ld\n" + "Writes : %-10ld Others : %-10ld\n" + "Disconnects : %-10ld Aborts : %-10ld\n" + "Resets : %-10ld\n", + info->info.stats.queues, info->info.stats.removes, + info->info.stats.fins, info->info.stats.reads, + info->info.stats.writes, info->info.stats.miscs, + info->info.stats.disconnects, info->info.stats.aborts, + info->info.stats.resets); + + pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none"); + + for (scd = host->host_queue; scd; scd = scd->next) { + int len; + + proc_print_scsidevice (scd, buffer, &len, pos); + pos += len; + pos += sprintf (buffer+pos, "Extensions: "); + if (scd->tagged_supported) + pos += sprintf (buffer+pos, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", + scd->current_tag); + pos += sprintf (buffer+pos, "\n"); + + if (pos + begin < offset) { + begin += pos; + pos = 0; + } + if (pos + begin > offset + length) + break; + } + + *start = buffer + (offset - begin); + pos -= offset - begin; + if (pos > length) + pos = length; + + return pos; +} + +#ifdef MODULE +Scsi_Host_Template driver_template = CUMANASCSI_2; + +#include "../../scsi/scsi_module.c" +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/cumana_2.h new/linux/drivers/acorn/scsi/cumana_2.h --- old/linux/drivers/acorn/scsi/cumana_2.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/cumana_2.h Sun Feb 8 23:08:52 1998 @@ -0,0 +1,73 @@ +/* + * Cumana SCSI II driver + * + * Copyright (C) 1997 Russell King + */ +#ifndef CUMANA_2_H +#define CUMANA_2_H + +extern int cumanascsi_2_detect (Scsi_Host_Template *); +extern int cumanascsi_2_release (struct Scsi_Host *); +extern const char *cumanascsi_2_info (struct Scsi_Host *); +extern int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef CAN_QUEUE +/* + * Default queue size + */ +#define CAN_QUEUE 1 +#endif + +#ifndef SCSI_ID +/* + * Default SCSI host ID + */ +#define SCSI_ID 7 +#endif + +#include + +#ifndef HOSTS_C +#include "fas216.h" +#endif + +#define CUMANASCSI_2 { \ +proc_info: cumanascsi_2_proc_info, \ +name: "Cumana SCSI II", \ +detect: cumanascsi_2_detect, /* detect */ \ +release: cumanascsi_2_release, /* release */ \ +info: cumanascsi_2_info, /* info */ \ +command: fas216_command, /* command */ \ +queuecommand: fas216_queue_command, /* queuecommand */ \ +abort: fas216_abort, /* abort */ \ +reset: fas216_reset, /* reset */ \ +bios_param: scsicam_bios_param, /* biosparam */ \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: SCSI_ID, /* scsi host id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CAN_QUEUE, /* cmd per lun */ \ +unchecked_isa_dma: 0, /* unchecked isa dma */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +typedef struct { + FAS216_Info info; + + /* other info... */ + unsigned int cstatus; /* card status register */ + unsigned int dmaarea; /* Pseudo DMA area */ +} CumanaScsi2_Info; + +#define CSTATUS_IRQ (1 << 0) +#define CSTATUS_DRQ (1 << 1) + +#endif /* HOSTS_C */ + +#endif /* CUMANASCSI_2_H */ diff -ur --new-file old/linux/drivers/acorn/scsi/ecoscsi.c new/linux/drivers/acorn/scsi/ecoscsi.c --- old/linux/drivers/acorn/scsi/ecoscsi.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/ecoscsi.c Sat Feb 21 22:25:15 1998 @@ -0,0 +1,239 @@ +#define AUTOSENSE +/* #define PSEUDO_DMA */ + +/* + * EcoSCSI Generic NCR5380 driver + * + * Copyright 1995, Russell King + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * Options : + * + * PARITY - enable parity checking. Not supported. + * + * SCSI2 - enable support for SCSI-II tagged queueing. Untested. + * + * USLEEP - enable support for devices that don't disconnect. Untested. + */ + +/* + * $Log: ecoscsi_NCR5380.c,v $ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "ecoscsi.h" +#include "../../scsi/NCR5380.h" +#include "../../scsi/constants.h" + +static struct proc_dir_entry proc_scsi_ecoscsi = { + PROC_SCSI_GENERIC_NCR5380, 7, "ecoscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +static char ecoscsi_read(struct Scsi_Host *instance, int reg) +{ + int iobase = instance->io_port; + outb(reg | 8, iobase); + return inb(iobase + 1); +} + +static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value) +{ + int iobase = instance->io_port; + outb(reg | 8, iobase); + outb(value, iobase + 1); +} + +/* + * Function : ecoscsi_setup(char *str, int *ints) + * + * Purpose : LILO command line initialization of the overrides array, + * + * Inputs : str - unused, ints - array of integer parameters with ints[0] + * equal to the number of ints. + * + */ + +void ecoscsi_setup(char *str, int *ints) { +} + +/* + * Function : int ecoscsi_detect(Scsi_Host_Template * tpnt) + * + * Purpose : initializes ecoscsi NCR5380 driver based on the + * command line / compile time port and irq definitions. + * + * Inputs : tpnt - template for this SCSI adapter. + * + * Returns : 1 if a host adapter was found, 0 if not. + * + */ + +int ecoscsi_detect(Scsi_Host_Template * tpnt) +{ + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_ecoscsi; + + instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); + instance->io_port = 0x80ce8000; + instance->n_io_port = 144; + instance->irq = IRQ_NONE; + + if (check_region (instance->io_port, instance->n_io_port)) { + scsi_unregister (instance); + return 0; + } + + ecoscsi_write (instance, MODE_REG, 0x20); /* Is it really SCSI? */ + if (ecoscsi_read (instance, MODE_REG) != 0x20) { /* Write to a reg. */ + scsi_unregister(instance); + return 0; /* and try to read */ + } + ecoscsi_write( instance, MODE_REG, 0x00 ); /* it back. */ + if (ecoscsi_read (instance, MODE_REG) != 0x00) { + scsi_unregister(instance); + return 0; + } + + NCR5380_init(instance, 0); + request_region (instance->io_port, instance->n_io_port, "ecoscsi"); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) { + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq != IRQ_NONE) { + printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no); + printk("scsi%d: that the board had an interrupt!\n", instance->host_no); + } + + printk("scsi%d: at port %X irq", instance->host_no, instance->io_port); + if (instance->irq == IRQ_NONE) + printk ("s disabled"); + else + printk (" %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", + CAN_QUEUE, CMD_PER_LUN, ECOSCSI_PUBLIC_RELEASE); + printk("\nscsi%d:", instance->host_no); + NCR5380_print_options(instance); + printk("\n"); + return 1; +} + +int ecoscsi_release (struct Scsi_Host *shpnt) +{ + if (shpnt->irq != IRQ_NONE) + free_irq (shpnt->irq, NULL); + if (shpnt->io_port) + release_region (shpnt->io_port, shpnt->n_io_port); + return 0; +} + +const char * ecoscsi_info (struct Scsi_Host *spnt) { + return ""; +} + +#if 0 +#define STAT(p) inw(p + 144) + +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int iobase = instance->io_port; +printk("writing %p len %d\n",addr, len); + if(!len) return -1; + + while(1) + { + int status; + while(((status = STAT(iobase)) & 0x100)==0); + } +} + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int iobase = instance->io_port; + int iobase2= instance->io_port + 0x100; + unsigned char *start = addr; + int s; +printk("reading %p len %d\n",addr, len); + outb(inb(iobase + 128), iobase + 135); + while(len > 0) + { + int status,b,i, timeout; + timeout = 0x07FFFFFF; + while(((status = STAT(iobase)) & 0x100)==0) + { + timeout--; + if(status & 0x200 || !timeout) + { + printk("status = %p\n",status); + outb(0, iobase + 135); + return 1; + } + } + if(len >= 128) + { + for(i=0; i<64; i++) + { + b = inw(iobase + 136); + *addr++ = b; + *addr++ = b>>8; + } + len -= 128; + } + else + { + b = inw(iobase + 136); + *addr ++ = b; + len -= 1; + if(len) + *addr ++ = b>>8; + len -= 1; + } + } + outb(0, iobase + 135); + printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]); + return 1; +} +#endif +#undef STAT + +#include "../../scsi/NCR5380.c" + +#ifdef MODULE + +Scsi_Host_Template driver_template = ECOSCSI_NCR5380; + +#include "../../scsi/scsi_module.c" +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/ecoscsi.h new/linux/drivers/acorn/scsi/ecoscsi.h --- old/linux/drivers/acorn/scsi/ecoscsi.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/ecoscsi.h Sun Dec 28 18:18:59 1997 @@ -0,0 +1,93 @@ +/* + * Cumana Generic NCR5380 driver defines + * + * Copyright 1995, Russell King + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * $Log: ecoscsi_NCR5380.h,v $ + */ + +#ifndef ECOSCSI_NCR5380_H +#define ECOSCSI_NCR5380_H + +#define ECOSCSI_PUBLIC_RELEASE 1 + + +#ifndef ASM +int ecoscsi_abort (Scsi_Cmnd *); +int ecoscsi_detect (Scsi_Host_Template *); +int ecoscsi_release (struct Scsi_Host *); +const char *ecoscsi_info (struct Scsi_Host *); +int ecoscsi_reset(Scsi_Cmnd *, unsigned int); +int ecoscsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int ecoscsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#define ECOSCSI_NCR5380 { \ +name: "Serial Port EcoSCSI NCR5380", \ +detect: ecoscsi_detect, \ +release: ecoscsi_release, \ +info: ecoscsi_info, \ +queuecommand: ecoscsi_queue_command, \ +abort: ecoscsi_abort, \ +reset: ecoscsi_reset, \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: 7, /* id */ \ +sg_tablesize: SG_ALL, \ +cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C +#define NCR5380_implementation_fields \ + int port, ctrl + +#define NCR5380_local_declare() \ + struct Scsi_Host *_instance + +#define NCR5380_setup(instance) \ + _instance = instance + +#define NCR5380_read(reg) ecoscsi_read(_instance, reg) +#define NCR5380_write(reg, value) ecoscsi_write(_instance, reg, value) + +#define NCR5380_intr ecoscsi_intr +#define NCR5380_queue_command ecoscsi_queue_command +#define NCR5380_abort ecoscsi_abort +#define NCR5380_reset ecoscsi_reset +#define NCR5380_proc_info ecoscsi_proc_info + +#define BOARD_NORMAL 0 +#define BOARD_NCR53C400 1 + +#endif /* ndef HOSTS_C */ +#endif /* ndef ASM */ +#endif /* ECOSCSI_NCR5380_H */ + diff -ur --new-file old/linux/drivers/acorn/scsi/fas216.c new/linux/drivers/acorn/scsi/fas216.c --- old/linux/drivers/acorn/scsi/fas216.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/fas216.c Wed Feb 18 23:14:47 1998 @@ -0,0 +1,1575 @@ +/* + * linux/arch/arm/drivers/scsi/fas216.c + * + * Copyright (C) 1997 Russell King + * + * Based in information in qlogicfas.c by Tom Zerucha, Michael Griffith, and + * other sources. + * + * This is a generic driver. To use it, have a look at cumana_2.c. You + * should define your own structure that overlays FAS216_Info, eg: + * struct my_host_data { + * FAS216_Info info; + * ... my host specific data ... + * }; + * + * Changelog: + * 30-08-1997 RMK Created + * 14-09-1997 RMK Started disconnect support + * 08-02-1998 RMK Corrected real DMA support + * 15-02-1998 RMK Started sync xfer support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define FAS216_C + +#include "scsi.h" +#include "hosts.h" +#include "fas216.h" + +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_PATCH 2 + +#undef NO_DISCONNECTS +#undef DEBUG_CONNECT +#undef DEBUG_BUSSERVICE +#undef DEBUG_FUNCTIONDONE +#undef DEBUG_MESSAGES + +static char *fas216_bus_phase (int stat) +{ + static char *phases[] = { + "DATA OUT", "DATA IN", + "COMMAND", "STATUS", + "MISC OUT", "MISC IN", + "MESG OUT", "MESG IN" + }; + + return phases[stat & STAT_BUSMASK]; +} + +static char fas216_target (FAS216_Info *info) +{ + if (info->SCpnt) + return '0' + info->SCpnt->target; + else + return 'H'; +} + +static void fas216_done (FAS216_Info *info, unsigned int result); + +/* Function: int fas216_clockrate (unsigned int clock) + * Purpose : calculate correct value to be written into clock conversion + * factor register. + * Params : clock - clock speed in MHz + * Returns : CLKF_ value + */ +static int fas216_clockrate (int clock) +{ + if (clock <= 10 || clock > 40) { + printk(KERN_CRIT + "fas216: invalid clock rate: check your driver!\n"); + clock = -1; + } else + clock = ((clock - 1) / 5 + 1) & 7; + + return clock; +} + +/* Function: int fas216_syncperiod(FAS216_Info *info, int ns) + * Purpose : Calculate value to be loaded into the STP register + * for a given period in ns + * Params : info - state structure for interface connected to device + * : ns - period in ns (between subsequent bytes) + * Returns : Value suitable for REG_STP + */ +static int fas216_syncperiod(FAS216_Info *info, int ns) +{ + int value = (info->ifcfg.clockrate * ns) / 1000; + + if (value < 4) + value = 4; + else if value > 35) + value = 35; + + return value & 31; +} + +/* Function: void fas216_updateptrs (FAS216_Info *info, int bytes_transferred) + * Purpose : update data pointers after transfer suspended/paused + * Params : info - interface's local pointer to update + * bytes_transferred - number of bytes transferred + */ +static void +fas216_updateptrs (FAS216_Info *info, int bytes_transferred) +{ + unsigned char *ptr = info->scsi.SCp.ptr; + unsigned int residual = info->scsi.SCp.this_residual; + + info->SCpnt->request_bufflen -= bytes_transferred; + + while (residual <= bytes_transferred && bytes_transferred) { + /* We have used up this buffer */ + bytes_transferred -= residual; + if (info->scsi.SCp.buffers_residual) { + info->scsi.SCp.buffer++; + info->scsi.SCp.buffers_residual--; + ptr = (unsigned char *)info->scsi.SCp.buffer->address; + residual = info->scsi.SCp.buffer->length; + } else { + ptr = NULL; + residual = 0; + } + } + + residual -= bytes_transferred; + ptr += bytes_transferred; + + info->scsi.SCp.ptr = ptr; + info->scsi.SCp.this_residual = residual; +} + +/* Function: void fas216_pio (FAS216_Info *info, fasdmadir_t direction) + * Purpose : transfer data off of/on to card using programmed IO + * Params : info - interface to transfer data to/from + * direction - direction to transfer data (DMA_OUT/DMA_IN) + * Notes : this is incredibly slow + */ +static void +fas216_pio (FAS216_Info *info, fasdmadir_t direction) +{ + unsigned int length = info->scsi.SCp.this_residual; + char *ptr = info->scsi.SCp.ptr; + + if (direction == DMA_OUT) { + while (length > 0) { + if ((inb(REG_CFIS(info)) & CFIS_CF) < 8) { + outb(*ptr++, REG_FF(info)); + length -= 1; + } else if (inb(REG_STAT(info)) & STAT_INT) + break; + } + } else { + while (length > 0) { + if ((inb(REG_CFIS(info)) & CFIS_CF) != 0) { + *ptr++ = inb(REG_FF(info)); + length -= 1; + } else if (inb(REG_STAT(info)) & STAT_INT) + break; + } + } + + if (length == 0) { + if (info->scsi.SCp.buffers_residual) { + info->scsi.SCp.buffer++; + info->scsi.SCp.buffers_residual--; + ptr = (unsigned char *)info->scsi.SCp.buffer->address; + length = info->scsi.SCp.buffer->length; + } else { + ptr = NULL; + length = 0; + } + } + + info->scsi.SCp.ptr = ptr; + info->scsi.SCp.this_residual = length; +} + +/* Function: void fas216_starttransfer(FAS216_Info *info, + * fasdmadir_t direction) + * Purpose : Start a DMA/PIO transfer off of/on to card + * Params : info - interface from which device disconnected from + * direction - transfer direction (DMA_OUT/DMA_IN) + */ +static void +fas216_starttransfer(FAS216_Info *info, fasdmadir_t direction) +{ + fasdmatype_t dmatype; + + info->scsi.phase = (direction == DMA_OUT) ? + PHASE_DATAOUT : PHASE_DATAIN; + + if (info->dma.transfer_type == fasdma_real_block || + info->dma.transfer_type == fasdma_real_all) { + unsigned long total, residual; + + if (info->dma.transfer_type == fasdma_real_block) + total = info->scsi.SCp.this_residual; + else + total = info->SCpnt->request_bufflen; + + residual = (inb(REG_CFIS(info)) & CFIS_CF) + + inb(REG_CTCL(info)) + + (inb(REG_CTCM(info)) << 8) + + (inb(REG_CTCH(info)) << 16); + fas216_updateptrs (info, total - residual); + info->dma.transfer_type = fasdma_none; + } + + if (!info->scsi.SCp.ptr) { + printk ("scsi%d.%c: null buffer passed to " + "fas216_starttransfer\n", info->host->host_no, + fas216_target (info)); + return; + } + + dmatype = fasdma_none; + if (info->dma.setup) + dmatype = info->dma.setup(info->host, &info->scsi.SCp, + direction); + + info->dma.transfer_type = dmatype; + + switch (dmatype) { + case fasdma_none: + outb(info->scsi.SCp.this_residual, REG_STCL(info)); + outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); + outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + outb(CMD_TRANSFERINFO, REG_CMD(info)); + fas216_pio (info, direction); + break; + + case fasdma_pseudo: { + int transferred; + + outb(info->scsi.SCp.this_residual, REG_STCL(info)); + outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); + outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info)); + + transferred = + info->dma.pseudo(info->host, &info->scsi.SCp, + direction, info->SCpnt->transfersize); + + fas216_updateptrs (info, transferred); + } + break; + + case fasdma_real_block: + outb(info->scsi.SCp.this_residual, REG_STCL(info)); + outb(info->scsi.SCp.this_residual >> 8, REG_STCM(info)); + outb(info->scsi.SCp.this_residual >> 16, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + + outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info)); + break; + + case fasdma_real_all: + outb(info->SCpnt->request_bufflen, REG_STCL(info)); + outb(info->SCpnt->request_bufflen >> 8, REG_STCM(info)); + outb(info->SCpnt->request_bufflen >> 16, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + + outb(CMD_TRANSFERINFO | CMD_WITHDMA, REG_CMD(info)); + break; + } +} + +/* Function: void fas216_stoptransfer (FAS216_Info *info) + * Purpose : Stop a DMA transfer onto / off of the card + * Params : info - interface from which device disconnected from + */ +static void +fas216_stoptransfer (FAS216_Info *info) +{ + if (info->dma.transfer_type == fasdma_real_block || + info->dma.transfer_type == fasdma_real_all) { + unsigned long total, residual; + + if (info->dma.stop) + info->dma.stop (info->host, &info->scsi.SCp); + + if (info->dma.transfer_type == fasdma_real_block) + total = info->scsi.SCp.this_residual; + else + total = info->SCpnt->request_bufflen; + + residual = (inb(REG_CFIS(info)) & CFIS_CF) + + inb(REG_CTCL(info)) + + (inb(REG_CTCM(info)) << 8) + + (inb(REG_CTCH(info)) << 16); + fas216_updateptrs (info, total - residual); + + info->dma.transfer_type = fasdma_none; + } +} + +/* Function: void fas216_disconnected_intr (FAS216_Info *info) + * Purpose : handle device disconnection + * Params : info - interface from which device disconnected from + */ +static void +fas216_disconnect_intr (FAS216_Info *info) +{ +#ifdef DEBUG_CONNECT + printk("scsi%d.%c: disconnect phase=%02X\n", info->host->host_no, + fas216_target (info), info->scsi.phase); +#endif + msgqueue_flush (&info->scsi.msgs); + + switch (info->scsi.phase) { + case PHASE_SELECTION: /* while selecting - no target */ + fas216_done (info, DID_NO_CONNECT); + break; + + case PHASE_DISCONNECT: /* message in - disconnecting */ + outb(CMD_ENABLESEL, REG_CMD(info)); + info->scsi.disconnectable = 1; + info->scsi.reconnected.tag = 0; + info->scsi.phase = PHASE_IDLE; + info->stats.disconnects += 1; + break; + + case PHASE_DONE: /* at end of command - complete */ + fas216_done (info, DID_OK); + break; + + case PHASE_AFTERMSGOUT: /* message out - possible ABORT message */ + if (info->scsi.last_message == ABORT) { + info->scsi.aborting = 0; + fas216_done (info, DID_ABORT); + break; + } + + default: /* huh? */ + printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %d\n", + info->host->host_no, fas216_target (info), info->scsi.phase); + fas216_stoptransfer(info); + fas216_done (info, DID_ERROR); + break; + } +} + +/* Function: void fas216_reselected_intr (FAS216_Info *info) + * Purpose : Start reconnection of a device + * Params : info - interface which was reselected + */ +static void +fas216_reselected_intr (FAS216_Info *info) +{ + unsigned char target, identify_msg, ok; + + if (info->scsi.phase == PHASE_SELECTION && info->SCpnt) { + Scsi_Cmnd *SCpnt = info->SCpnt; + + info->origSCpnt = SCpnt; + info->SCpnt = NULL; + + if (info->device[SCpnt->target].negstate == syncneg_sent) + info->device[SCpnt->target].negstate = syncneg_start; + } + +#ifdef DEBUG_CONNECT + printk("scsi%d.%c: reconnect phase=%02X\n", info->host->host_no, + fas216_target (info), info->scsi.phase); +#endif + + msgqueue_flush (&info->scsi.msgs); + + if ((inb(REG_CFIS(info)) & CFIS_CF) != 2) { + printk (KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n", + info->host->host_no); + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT; + outb(CMD_MSGACCEPTED, REG_CMD(info)); + return; + } + + target = inb(REG_FF(info)); + identify_msg = inb(REG_FF(info)); + + ok = 1; + if (!(target & (1 << info->host->this_id))) { + printk (KERN_ERR "scsi%d.H: invalid host id on reselect\n", info->host->host_no); + ok = 0; + } + + if (!(identify_msg & 0x80)) { + printk (KERN_ERR "scsi%d.H: no IDENTIFY message on reselect, got msg %02X\n", + info->host->host_no, identify_msg); + ok = 0; + } + + if (!ok) { + /* + * Something went wrong - abort the command on + * the target. Should this be INITIATOR_ERROR ? + */ + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT; + outb(CMD_MSGACCEPTED, REG_CMD(info)); + return; + } + + target &= ~(1 << info->host->this_id); + switch (target) { + case 1: target = 0; break; + case 2: target = 1; break; + case 4: target = 2; break; + case 8: target = 3; break; + case 16: target = 4; break; + case 32: target = 5; break; + case 64: target = 6; break; + case 128: target = 7; break; + default: target = info->host->this_id; break; + } + + identify_msg &= 7; + info->scsi.reconnected.target = target; + info->scsi.reconnected.lun = identify_msg; + info->scsi.reconnected.tag = 0; + + ok = 0; + if (info->scsi.disconnectable && info->SCpnt && + info->SCpnt->target == target && info->SCpnt->lun == identify_msg) + ok = 1; + + if (!ok && queue_probetgtlun (&info->queues.disconnected, target, identify_msg)) + ok = 1; + + if (ok) { + info->scsi.phase = PHASE_RECONNECTED; + outb(target, REG_SDID(info)); + } else { + /* + * Our command structure not found - abort the command on the target + * Should this be INITIATOR_ERROR ? + */ + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT; + } + outb(CMD_MSGACCEPTED, REG_CMD(info)); +} + +/* Function: void fas216_finish_reconnect (FAS216_Info *info) + * Purpose : finish reconnection sequence for device + * Params : info - interface which caused function done interrupt + */ +static void +fas216_finish_reconnect (FAS216_Info *info) +{ +#ifdef DEBUG_CONNECT +printk ("Connected: %1X %1X %02X, reconnected: %1X %1X %02X\n", + info->SCpnt->target, info->SCpnt->lun, info->SCpnt->tag, + info->scsi.reconnected.target, info->scsi.reconnected.lun, + info->scsi.reconnected.tag); +#endif + + if (info->scsi.disconnectable && info->SCpnt) { + info->scsi.disconnectable = 0; + if (info->SCpnt->target == info->scsi.reconnected.target && + info->SCpnt->lun == info->scsi.reconnected.lun && + info->SCpnt->tag == info->scsi.reconnected.tag) { +#ifdef DEBUG_CONNECT + printk ("scsi%d.%c: reconnected", + info->host->host_no, fas216_target (info)); +#endif + } else { + queue_add_cmd_tail (&info->queues.disconnected, info->SCpnt); +#ifdef DEBUG_CONNECT + printk ("scsi%d.%c: had to move command to disconnected queue\n", + info->host->host_no, fas216_target (info)); +#endif + info->SCpnt = NULL; + } + } + if (!info->SCpnt) { + info->SCpnt = queue_remove_tgtluntag (&info->queues.disconnected, + info->scsi.reconnected.target, + info->scsi.reconnected.lun, + info->scsi.reconnected.tag); +#ifdef DEBUG_CONNECT + printk ("scsi%d.%c: had to get command", + info->host->host_no, fas216_target (info)); +#endif + } + if (!info->SCpnt) { + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT; + info->scsi.aborting = 1; + } else { + /* + * Restore data pointer from SAVED data pointer + */ + info->scsi.SCp = info->SCpnt->SCp; +#ifdef DEBUG_CONNECT + printk (", data pointers: [%p, %X]", + info->scsi.SCp.ptr, info->scsi.SCp.this_residual); +#endif + } +#ifdef DEBUG_CONNECT + printk ("\n"); +#endif +} + +/* Function: void fas216_message (FAS216_Info *info) + * Purpose : handle a function done interrupt from FAS216 chip + * Params : info - interface which caused function done interrupt + */ +static void fas216_message (FAS216_Info *info) +{ + unsigned char message[16]; + unsigned int msglen = 1; + + message[0] = inb(REG_FF(info)); + + if (message[0] == EXTENDED_MESSAGE) { + message[1] = inb(REG_FF(info)); + + for (msglen = 2; msglen < message[1]; msglen++) + message[msglen] = inb(REG_FF(info)); + } + +#ifdef DEBUG_MESSAGES + { + int i; + + printk ("scsi%d.%c: message in: ", + info->host->host_no, fas216_target (info)); + for (i = 0; i < msglen; i++) + printk ("%02X ", message[i]); + printk ("\n"); + } +#endif + if (info->scsi.phase == PHASE_RECONNECTED) { + if (message[0] == SIMPLE_QUEUE_TAG) + info->scsi.reconnected.tag = message[1]; + fas216_finish_reconnect (info); + info->scsi.phase = PHASE_MSGIN; + } + + switch (message[0]) { + case COMMAND_COMPLETE: + printk ("fas216: command complete with no status in MESSAGE_IN?\n"); + break; + + case SAVE_POINTERS: + /* + * Save current data pointer to SAVED data pointer + */ + info->SCpnt->SCp = info->scsi.SCp; +#if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT) + printk ("scsi%d.%c: save data pointers: [%p, %X]\n", + info->host->host_no, fas216_target (info), + info->scsi.SCp.ptr, info->scsi.SCp.this_residual); +#endif + break; + + case RESTORE_POINTERS: + /* + * Restore current data pointer from SAVED data pointer + */ + info->scsi.SCp = info->SCpnt->SCp; +#if defined (DEBUG_MESSAGES) || defined (DEBUG_CONNECT) + printk ("scsi%d.%c: restore data pointers: [%p, %X]\n", + info->host->host_no, fas216_target (info), + info->scsi.SCp.ptr, info->scsi.SCp.this_residual); +#endif + break; + + case DISCONNECT: + info->scsi.phase = PHASE_DISCONNECT; + break; + + case MESSAGE_REJECT: + printk ("scsi%d.%c: reject, last message %04X\n", + info->host->host_no, fas216_target (info), + info->scsi.last_message); + break; + + case SIMPLE_QUEUE_TAG: + /* handled above */ + printk ("scsi%d.%c: reconnect queue tag %02X\n", + info->host->host_no, fas216_target (info), + message[1]); + break; + + case EXTENDED_MESSAGE: + switch (message[2]) { + case EXTENDED_SDTR: /* Sync transfer negociation request/reply */ + + case EXTENDED_WDTR: /* Wide transfer negociation request/reply */ + /* We don't do wide transfers - reject message */ + default: + printk("scsi%d.%c: unrecognised extended message %02X, rejecting\n", + info->host->host_no, fas216_target (info), + message[2]); + msgqueue_flush (&info->scsi.msgs); + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT; + break; + } + break; + + default: + printk ("scsi%d.%c: unrecognised message %02X, rejecting\n", + info->host->host_no, fas216_target (info), + message[0]); + msgqueue_flush (&info->scsi.msgs); + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, MESSAGE_REJECT); + info->scsi.phase = PHASE_MSGOUT; + break; + } + outb(CMD_MSGACCEPTED, REG_CMD(info)); +} + +/* Function: void fas216_busservice_intr (FAS216_Info *info, unsigned int stat, unsigned int ssr) + * Purpose : handle a bus service interrupt from FAS216 chip + * Params : info - interface which caused bus service interrupt + * stat - Status register contents + * ssr - SCSI Status register contents + */ +static void fas216_busservice_intr (FAS216_Info *info, unsigned int stat, unsigned int ssr) +{ + int i; +#ifdef DEBUG_BUSSERVICE + printk("scsi%d.%c: bus service: stat=%02X ssr=%02X phase=%02X\n", + info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase); +#endif + switch (ssr & IS_BITS) { + case IS_COMPLETE: /* last action completed */ + outb(CMD_NOP, REG_CMD(info)); + + switch (info->scsi.phase) { + case PHASE_SELECTION: /* while selecting - selected target */ + switch (stat & STAT_BUSMASK) { + case STAT_DATAOUT: /* data out phase */ + fas216_starttransfer (info, DMA_OUT); + break; + + case STAT_DATAIN: /* data in phase */ + fas216_starttransfer (info, DMA_IN); + break; + + case STAT_STATUS: /* status phase */ + info->scsi.phase = PHASE_STATUS; + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + break; + + case STAT_MESGIN: /* message in phase */ + info->scsi.phase = PHASE_MSGIN; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: /* other */ + printk ("scsi%d.%c: bus phase %s after connect?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + break; + } + break; + + case PHASE_DATAIN: /* while transfering data in */ + switch (stat & STAT_BUSMASK) { + case STAT_DATAIN: /* continue data in phase */ + fas216_starttransfer (info, DMA_IN); + break; + + case STAT_STATUS: + fas216_stoptransfer(info); + info->scsi.phase = PHASE_STATUS; + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + break; + + case STAT_MESGIN: /* message in phase */ + fas216_stoptransfer(info); + info->scsi.phase = PHASE_MSGIN; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: bus phase %s after data in?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_DATAOUT: /* while transfering data out */ + switch (stat & STAT_BUSMASK) { + case STAT_DATAOUT: + fas216_starttransfer (info, DMA_OUT); + break; + + case STAT_STATUS: + fas216_stoptransfer(info); + info->scsi.phase = PHASE_STATUS; + outb(CMD_FLUSHFIFO, REG_CMD(info)); + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + break; + + case STAT_MESGIN: /* message in phase */ + fas216_stoptransfer(info); + info->scsi.phase = PHASE_MSGIN; + outb(CMD_FLUSHFIFO, REG_CMD(info)); + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: bus phase %s after data out?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_RECONNECTED: /* newly reconnected device */ + /* + * Command reconnected - if MESGIN, get message - it may be + * the tag. If not, get command out of the disconnected queue + */ + switch (stat & STAT_BUSMASK) { + case STAT_MESGIN: + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + case STAT_STATUS: + fas216_finish_reconnect (info); + info->scsi.phase = PHASE_STATUS; + outb(CMD_INITCMDCOMPLETE, REG_CMD(info)); + break; + + case STAT_DATAOUT: /* data out phase */ + fas216_finish_reconnect (info); + fas216_starttransfer (info, DMA_OUT); + break; + + case STAT_DATAIN: /* data in phase */ + fas216_finish_reconnect (info); + fas216_starttransfer (info, DMA_IN); + break; + + default: + printk ("scsi%d.%c: bus phase %s after reconnect?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_MSGIN: + switch (stat & STAT_BUSMASK) { + case STAT_MESGIN: + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: bus phase %s after message in?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_MSGOUT: + if ((stat & STAT_BUSMASK) != STAT_MESGOUT) { + printk ("scsi%d.%c: didn't manage MESSAGE OUT phase\n", + info->host->host_no, fas216_target (info)); + } else { + unsigned int msglen; + + msglen = msgqueue_msglength (&info->scsi.msgs); + + outb(CMD_FLUSHFIFO, REG_CMD(info)); + + if (msglen == 0) + outb(NOP, REG_FF(info)); + else { + char *msg; + + while ((msg = msgqueue_getnextmsg (&info->scsi.msgs, &msglen)) != NULL) { + for (i = 0; i < msglen; i++) + outb(msg[i], REG_FF(info)); + } + } + outb(CMD_TRANSFERINFO, REG_CMD(info)); + info->scsi.phase = PHASE_AFTERMSGOUT; + } + break; + + case PHASE_AFTERMSGOUT: + switch (stat & STAT_BUSMASK) { + case STAT_MESGIN: + info->scsi.phase = PHASE_MSGIN; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: bus phase %s after message out\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + } + break; + + case PHASE_DISCONNECT: + printk ("scsi%d.%c: disconnect message received, but bus service %s?\n", + info->host->host_no, fas216_target (info), + fas216_bus_phase (stat)); + outb(CMD_SETATN, REG_CMD(info)); + msgqueue_addmsg (&info->scsi.msgs, 1, ABORT); + info->scsi.phase = PHASE_MSGOUT; + info->scsi.aborting = 1; + outb(CMD_TRANSFERINFO, REG_CMD(info)); + break; + + default: + printk ("scsi%d.%c: internal phase %d for bus service?" + " What do I do with this?\n", + info->host->host_no, fas216_target (info), + info->scsi.phase); + } + break; + + default: + printk ("scsi%d.%c: bus service at step %d?\n", + info->host->host_no, fas216_target (info), + ssr & IS_BITS); + } +} + +/* Function: void fas216_funcdone_intr (FAS216_Info *info, unsigned int stat, unsigned int ssr) + * Purpose : handle a function done interrupt from FAS216 chip + * Params : info - interface which caused function done interrupt + * stat - Status register contents + * ssr - SCSI Status register contents + */ +static void fas216_funcdone_intr (FAS216_Info *info, unsigned int stat, unsigned int ssr) +{ + int status, message; +#ifdef DEBUG_FUNCTIONDONE + printk("scsi%d.%c: function done: stat=%X ssr=%X phase=%02X\n", + info->host->host_no, fas216_target(info), stat, ssr, info->scsi.phase); +#endif + switch (info->scsi.phase) { + case PHASE_STATUS: /* status phase - read status and msg */ + status = inb(REG_FF(info)); + message = inb(REG_FF(info)); + info->scsi.SCp.Message = message; + info->scsi.SCp.Status = status; + info->scsi.phase = PHASE_DONE; + outb(CMD_MSGACCEPTED, REG_CMD(info)); + break; + + case PHASE_IDLE: /* reselected? */ + case PHASE_MSGIN: /* message in phase */ + case PHASE_RECONNECTED: /* reconnected command */ + if ((stat & STAT_BUSMASK) == STAT_MESGIN) { + fas216_message (info); + break; + } + + default: + printk ("scsi%d.%c: internal phase %d for function done?" + " What do I do with this?\n", + info->host->host_no, fas216_target (info), + info->scsi.phase); + } +} + +/* Function: void fas216_intr (struct Scsi_Host *instance) + * Purpose : handle interrupts from the interface to progress a command + * Params : instance - interface to service + */ +void fas216_intr (struct Scsi_Host *instance) +{ + FAS216_Info *info = (FAS216_Info *)instance->hostdata; + unsigned char isr, ssr, stat; + + stat = inb(REG_STAT(info)); + ssr = inb(REG_IS(info)); + isr = inb(REG_INST(info)); + + if (isr & INST_BUSRESET) + printk ("scsi%d.H: fas216: bus reset detected\n", instance->host_no); + else if (isr & INST_ILLEGALCMD) + printk (KERN_CRIT "scsi%d.H: illegal command given\n", instance->host_no); + else if (isr & INST_DISCONNECT) + fas216_disconnect_intr (info); + else if (isr & INST_RESELECTED) /* reselected */ + fas216_reselected_intr (info); + else if (isr & INST_BUSSERVICE) /* bus service request */ + fas216_busservice_intr (info, stat, ssr); + else if (isr & INST_FUNCDONE) /* function done */ + fas216_funcdone_intr (info, stat, ssr); + else + printk ("scsi%d.%c: unknown interrupt received:" + " phase %d isr %02X ssr %02X stat %02X\n", + instance->host_no, fas216_target (info), + info->scsi.phase, isr, ssr, stat); +} + +/* Function: void fas216_kick (FAS216_Info *info) + * Purpose : kick a command to the interface - interface should be idle + * Params : info - our host interface to kick + * Notes : Interrupts are always disabled! + */ +static void fas216_kick (FAS216_Info *info) +{ + Scsi_Cmnd *SCpnt; + int i, msglen, from_queue = 0; + + if (info->origSCpnt) { + SCpnt = info->origSCpnt; + info->origSCpnt = NULL; + } else + SCpnt = NULL; + + /* retrieve next command */ + if (!SCpnt) { + SCpnt = queue_remove_exclude(&info->queues.issue, info->busyluns); + from_queue = 1; + } + + if (!SCpnt) /* no command pending - just exit */ + return; + + if (info->scsi.disconnectable && info->SCpnt) { + queue_add_cmd_tail (&info->queues.disconnected, info->SCpnt); + info->scsi.disconnectable = 0; + info->SCpnt = NULL; + printk("scsi%d.%c: moved command to disconnected queue\n", + info->host->host_no, fas216_target (info)); + } + + /* + * tagged queuing - allocate a new tag to this command + */ + if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) { + SCpnt->device->current_tag += 1; + if (SCpnt->device->current_tag == 0) + SCpnt->device->current_tag = 1; + SCpnt->tag = SCpnt->device->current_tag; + } + + /* + * claim host busy + */ + info->scsi.phase = PHASE_SELECTION; + info->SCpnt = SCpnt; + info->scsi.SCp = SCpnt->SCp; + info->dma.transfer_type = fasdma_none; + +#ifdef DEBUG_CONNECT + printk("scsi%d.%c: starting cmd %02X", + info->host->host_no, '0' + SCpnt->target, + SCpnt->cmnd[0]); +#endif + + if (from_queue) { +#ifdef SCSI2_TAG + if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE) { + SCpnt->device->current_tag += 1; + if (SCpnt->device->current_tag == 0) + SCpnt->device->current_tag = 1; + SCpnt->tag = SCpnt->device->current_tag; + } else +#endif + set_bit(SCpnt->target * 8 + SCpnt->lun, info->busyluns); + + info->stats.removes += 1; + switch (SCpnt->cmnd[0]) { + case WRITE_6: + case WRITE_10: + case WRITE_12: + info->stats.writes += 1; + break; + case READ_6: + case READ_10: + case READ_12: + info->stats.reads += 1; + break; + default: + info->stats.miscs += 1; + break; + } + } + + /* build outgoing message bytes */ + msgqueue_flush (&info->scsi.msgs); + if (info->device[SCpnt->target].disconnect_ok) + msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(1, SCpnt->lun)); + else + msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(0, SCpnt->lun)); + + /* add tag message if required */ + if (SCpnt->tag) + msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag); + + /* add synchronous negociation */ + if (info->device[SCpnt->target].negstate == syncneg_start) { + info->device[SCpnt->target].negstate = syncneg_sent; + msgqueue_addmsg(&info->scsi.msgs, 5, + EXTENDED_MESSAGE, 3, EXTENDED_SDTR, + 1000 / info->ifcfg.clockrate, + info->ifcfg.sync_max_depth); + } + + /* following what the ESP driver says */ + outb(0, REG_STCL(info)); + outb(0, REG_STCM(info)); + outb(0, REG_STCH(info)); + outb(CMD_NOP | CMD_WITHDMA, REG_CMD(info)); + + /* flush FIFO */ + outb(CMD_FLUSHFIFO, REG_CMD(info)); + + /* load bus-id and timeout */ + outb(BUSID(SCpnt->target), REG_SDID(info)); + outb(info->ifcfg.select_timeout, REG_STIM(info)); + + /* synchronous transfers */ + outb(info->device[SCpnt->target].sof, REG_SOF(info)); + outb(info->device[SCpnt->target].stp, REG_STP(info)); + + msglen = msgqueue_msglength (&info->scsi.msgs); + + if (msglen == 1 || msglen == 3) { + char *msg; + + /* load message bytes */ + while ((msg = msgqueue_getnextmsg(&info->scsi.msgs, &msglen)) != NULL) { + for (i = 0; i < msglen; i++) + outb(msg[i], REG_FF(info)); + } + + /* load command */ + for (i = 0; i < SCpnt->cmd_len; i++) + outb(SCpnt->cmnd[i], REG_FF(info)); + + if (msglen == 1) + outb(CMD_SELECTATN, REG_CMD(info)); + else + outb(CMD_SELECTATN3, REG_CMD(info)); + } else { + outb(CMD_SELECTATNSTOP, REG_CMD(info)); + } + +#ifdef DEBUG_CONNECT + printk(", data pointers [%p, %X]\n", + info->scsi.SCp.ptr, info->scsi.SCp.this_residual); +#endif + /* should now get either DISCONNECT or (FUNCTION DONE with BUS SERVICE) intr */ +} + +/* Function: void fas216_done (FAS216_Info *info, unsigned int result) + * Purpose : complete processing for command + * Params : info - interface that completed + * result - driver byte of result + */ +static void fas216_done (FAS216_Info *info, unsigned int result) +{ + Scsi_Cmnd *SCpnt = info->SCpnt; + + if (info->scsi.aborting) { + printk ("scsi%d.%c: uncaught abort - returning DID_ABORT\n", + info->host->host_no, fas216_target (info)); + result = DID_ABORT; + info->scsi.aborting = 0; + } + + info->stats.fins += 1; + + if (SCpnt) { + info->scsi.phase = PHASE_IDLE; + info->SCpnt = NULL; + + SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 | + info->scsi.SCp.Status; + + /* + * In theory, this should not happen, but just in case it does. + */ + if (info->scsi.SCp.ptr && result == DID_OK) { + switch (status_byte (SCpnt->result)) { + case CHECK_CONDITION: + case COMMAND_TERMINATED: + case BUSY: + case QUEUE_FULL: + case RESERVATION_CONFLICT: + break; + + default: + printk (KERN_ERR "scsi%d.H: incomplete data transfer " + "detected: result=%08X command=", + info->host->host_no, SCpnt->result); + print_command (SCpnt->cmnd); + } + } +#ifdef DEBUG_CONNECT + printk ("scsi%d.%c: scsi command (%p) complete, result=%08X\n", + info->host->host_no, fas216_target (info), + SCpnt, SCpnt->result); +#endif + + if (!SCpnt->scsi_done) + panic ("scsi%d.H: null scsi_done function in fas216_done", info->host->host_no); + + clear_bit (SCpnt->target * 8 + SCpnt->lun, info->busyluns); + + SCpnt->scsi_done (SCpnt); + } else + panic ("scsi%d.H: null command in fas216_done", info->host->host_no); + + if (info->scsi.irq != NO_IRQ) + fas216_kick (info); +} + +/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) + * Purpose : queue a command for adapter to process. + * Params : SCpnt - Command to queue + * done - done function to call once command is complete + * Returns : 0 - success, else error + */ +int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + +#ifdef DEBUG_CONNECT + printk("scsi%d.%c: received queuable command (%p) %02X\n", + SCpnt->host->host_no, '0' + SCpnt->target, + SCpnt, SCpnt->cmnd[0]); +#endif + + SCpnt->scsi_done = done; + SCpnt->host_scribble = NULL; + SCpnt->result = 0; + SCpnt->SCp.Message = 0; + SCpnt->SCp.Status = 0; + + if (SCpnt->use_sg) { + unsigned long len = 0; + int buf; + + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + /* + * Calculate correct buffer length + */ + for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++) + len += SCpnt->SCp.buffer[buf].length; + SCpnt->request_bufflen = len; + } else { + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + } + + info->stats.queues += 1; + SCpnt->tag = 0; + + if (info->scsi.irq != NO_IRQ) { + unsigned long flags; + + /* add command into execute queue and let it complete under + * the drivers interrupts. + */ + if (!queue_add_cmd_ordered (&info->queues.issue, SCpnt)) { + SCpnt->result = DID_ERROR << 16; + done (SCpnt); + } + save_flags_cli (flags); + if (!info->SCpnt || info->scsi.disconnectable) + fas216_kick (info); + restore_flags (flags); + } else { + /* no interrupts to rely on - we'll have to handle the + * command ourselves. For now, we give up. + */ + SCpnt->result = DID_ERROR << 16; + done (SCpnt); + } + return 0; +} + +/* Function: void fas216_internal_done (Scsi_Cmnd *SCpnt) + * Purpose : trigger restart of a waiting thread in fas216_command + * Params : SCpnt - Command to wake + */ +static void fas216_internal_done (Scsi_Cmnd *SCpnt) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + + info->internal_done = 1; +} + +/* Function: int fas216_command (Scsi_Cmnd *SCpnt) + * Purpose : queue a command for adapter to process. + * Params : SCpnt - Command to queue + * Returns : scsi result code + */ +int fas216_command (Scsi_Cmnd *SCpnt) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + unsigned long flags; + + info->internal_done = 0; + fas216_queue_command (SCpnt, fas216_internal_done); + + /* + * This wastes time, since we can't return until the command is + * complete. We can't seep either since we may get re-entered! + * However, we must re-enable interrupts, or else we'll be + * waiting forever. + */ + save_flags (flags); + sti (); + + while (!info->internal_done) + barrier (); + + restore_flags (flags); + + return SCpnt->result; +} + +/* Prototype: void fas216_reportstatus(Scsi_Cmnd **SCpntp1, + * Scsi_Cmnd **SCpntp2, int result) + * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 + * Params : SCpntp1 - pointer to command to return + * SCpntp2 - pointer to command to check + * result - result to pass back to mid-level done function + * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command + * structure as *SCpntp2. + */ +static void fas216_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, + int result) +{ + Scsi_Cmnd *SCpnt = *SCpntp1; + + if (SCpnt) { + *SCpntp1 = NULL; + + SCpnt->result = result; + SCpnt->scsi_done (SCpnt); + } + + if (SCpnt == *SCpntp2) + *SCpntp2 = NULL; +} + +/* Function: int fas216_abort (Scsi_Cmnd *SCpnt) + * Purpose : abort a command if something horrible happens. + * Params : SCpnt - Command that is believed to be causing a problem. + * Returns : one of SCSI_ABORT_ macros. + */ +int fas216_abort (Scsi_Cmnd *SCpnt) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + int result = SCSI_ABORT_SNOOZE; + + info->stats.aborts += 1; + + printk(KERN_WARNING "scsi%d: fas216_abort: ", info->host->host_no); + + do { + /* If command is waiting in the issue queue, then we can + * simply remove the command and return abort status + */ + if (queue_removecmd (&info->queues.issue, SCpnt)) { + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done (SCpnt); + printk ("command on issue queue"); + result = SCSI_ABORT_SUCCESS; + break; + } + + /* If the command is on the disconencted queue, we need to + * reconnect to the device + */ + if (queue_cmdonqueue (&info->queues.disconnected, SCpnt)) + printk ("command on disconnected queue"); + + /* If the command is connected, we need to flag that the + * command needs to be aborted + */ + if (info->SCpnt == SCpnt) + printk ("command executing"); + + /* If the command is pending for execution, then again + * this is simple - we remove it and report abort status + */ + if (info->origSCpnt == SCpnt) { + info->origSCpnt = NULL; + SCpnt->result = DID_ABORT << 16; + SCpnt->scsi_done (SCpnt); + printk ("command waiting for execution"); + result = SCSI_ABORT_SUCCESS; + break; + } + } while (0); + + printk ("\n"); + + return result; +} + +/* Function: void fas216_reset_state(FAS216_Info *info) + * Purpose : Initialise driver internal state + * Params : info - state to initialise + */ +static void fas216_reset_state(FAS216_Info *info) +{ + int i; + + /* + * Clear out all stale info in our state structure + */ + memset (info->busyluns, 0, sizeof (info->busyluns)); + msgqueue_flush(&info->scsi.msgs); + info->scsi.reconnected.target = 0; + info->scsi.reconnected.lun = 0; + info->scsi.reconnected.tag = 0; + info->scsi.disconnectable = 0; + info->scsi.last_message = 0; + info->scsi.aborting = 0; + info->scsi.phase = PHASE_IDLE; + + for (i = 0; i < 8; i++) { +#ifndef NO_DISCONNECTS + info->device[i].disconnect_ok = 1; +#else + info->device[i].disconnect_ok = 0; +#endif + info->device[i].stp = fas216_syncperiod(info->ifcfg.asyncperiod); + info->device[i].sof = 0; +#ifdef SCSI2SYNC + info->device[i].negstate = syncneg_start; +#else + info->device[i].negstate = syncneg_complete; +#endif + } +} + +/* Function: void fas216_init_chip(FAS216_Info *info) + * Purpose : Initialise FAS216 state after reset + * Params : info - state structure for interface + */ +static void fas216_init_chip(FAS216_Info *info) +{ + outb(fas216_clockrate(info->ifcfg.clockrate), REG_CLKF(info)); + outb(info->scsi.cfg[0], REG_CNTL1(info)); + outb(info->scsi.cfg[1], REG_CNTL2(info)); + outb(info->scsi.cfg[2], REG_CNTL3(info)); + outb(info->ifcfg.select_timeout, REG_STIM(info)); + outb(0, REG_SOF(info)); + outb(fas216_syncperiod(info->ifcfg.asyncperiod), REG_STP(info)); + outb(info->scsi.cfg[0], REG_CNTL1(info)); +} + +/* Function: int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * Purpose : resets the adapter if something horrible happens. + * Params : SCpnt - Command that is believed to be causing a problem. + * reset_flags - flags indicating reset type that is believed + * to be required. + * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET + * macros. + */ +int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) +{ + FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; + Scsi_Cmnd *SCptr; + int result = 0; + + info->stats.resets += 1; + + printk(KERN_WARNING "scsi%d: fas216_reset: ", info->host->host_no); + + outb(info->scsi.cfg[3], REG_CNTL3(info)); + + fas216_stoptransfer(info); + fas216_reset_state(info); + + if (reset_flags & SCSI_RESET_SUGGEST_HOST_RESET) { + outb(CMD_RESETCHIP, REG_CMD(info)); + outb(CMD_NOP, REG_CMD(info)); + result |= SCSI_RESET_HOST_RESET; + } + + if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) { + outb(CMD_RESETSCSI, REG_CMD(info)); + outb(CMD_NOP, REG_CMD(info)); + result |= SCSI_RESET_BUS_RESET; + } + + if (!(reset_flags & + (SCSI_RESET_SUGGEST_BUS_RESET|SCSI_RESET_SUGGEST_HOST_RESET))) { + outb(CMD_RESETCHIP, REG_CMD(info)); + outb(CMD_NOP, REG_CMD(info)); + outb(CMD_RESETSCSI, REG_CMD(info)); + result |= SCSI_RESET_HOST_RESET | SCSI_RESET_BUS_RESET; + } + + if (result & SCSI_RESET_HOST_RESET) + fas216_init_chip(info); + + /* + * Signal all commands in progress have been reset + */ + fas216_reportstatus (&info->SCpnt, &SCpnt, DID_RESET << 16); + + while ((SCptr = queue_remove (&info->queues.disconnected)) != NULL) + fas216_reportstatus (&SCptr, &SCpnt, DID_RESET << 16); + + if (SCpnt) { + /* + * Command not found on disconnected queue, nor currently + * executing command - check pending commands + */ + if (info->origSCpnt == SCpnt) + info->origSCpnt = NULL; + + queue_removecmd(&info->queues.issue, SCpnt); + + SCpnt->result = DID_RESET << 16; + SCpnt->scsi_done (SCpnt); + } + + printk ("\n"); + + return result | SCSI_RESET_SUCCESS; +} + +/* Function: int fas216_init (struct Scsi_Host *instance) + * Purpose : initialise FAS/NCR/AMD SCSI ic. + * Params : instance - a driver-specific filled-out structure + * Returns : 0 on success + */ +int fas216_init (struct Scsi_Host *instance) +{ + FAS216_Info *info = (FAS216_Info *)instance->hostdata; + unsigned long flags; + int target_jiffies; + + info->host = instance; + info->scsi.cfg[0] = instance->this_id; + info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE; + info->scsi.cfg[2] = CNTL3_ADDIDCHK | CNTL3_G2CB | CNTL3_FASTSCSI | CNTL3_FASTCLK; + info->scsi.type = "unknown"; + info->SCpnt = NULL; + fas216_reset_state(info); + + memset (&info->stats, 0, sizeof (info->stats)); + + msgqueue_initialise (&info->scsi.msgs); + + if (!queue_initialise (&info->queues.issue)) + return 1; + + if (!queue_initialise (&info->queues.disconnected)) { + queue_free (&info->queues.issue); + return 1; + } + + outb(0, REG_CNTL3(info)); + outb(CNTL2_S2FE, REG_CNTL2(info)); + + if ((inb(REG_CNTL2(info)) & (~0xe0)) != CNTL2_S2FE) { + info->scsi.type = "NCR53C90"; + } else { + outb(0, REG_CNTL2(info)); + outb(0, REG_CNTL3(info)); + outb(5, REG_CNTL3(info)); + if (inb(REG_CNTL3(info)) != 5) { + info->scsi.type = "NCR53C90A"; + } else { + outb(0, REG_CNTL3(info)); + info->scsi.type = "NCR53C9x"; + } + } + + + outb(CNTL3_IDENABLE, REG_CNTL3(info)); + outb(0, REG_CNTL3(info)); + + outb(CMD_RESETCHIP, REG_CMD(info)); + outb(CMD_WITHDMA | CMD_NOP, REG_CMD(info)); + outb(CNTL2_ENF, REG_CNTL2(info)); + outb(CMD_RESETCHIP, REG_CMD(info)); + switch (inb(REG1_ID(info))) { + case 12: + info->scsi.type = "Am53CF94"; + break; + default: + break; + } + + udelay (300); + + /* now for the real initialisation */ + fas216_init_chip(info); + + outb(info->scsi.cfg[0] | CNTL1_DISR, REG_CNTL1(info)); + outb(CMD_RESETSCSI, REG_CMD(info)); + + /* scsi standard says 250ms */ + target_jiffies = jiffies + (25 * HZ) / 100; + save_flags (flags); + sti (); + + while (jiffies < target_jiffies) barrier (); + + restore_flags (flags); + + outb(info->scsi.cfg[0], REG_CNTL1(info)); + inb(REG_INST(info)); + + return 0; +} + +/* Function: int fas216_release (struct Scsi_Host *instance) + * Purpose : release all resources and put everything to bed for + * FAS/NCR/AMD SCSI ic. + * Params : instance - a driver-specific filled-out structure + * Returns : 0 on success + */ +int fas216_release (struct Scsi_Host *instance) +{ + FAS216_Info *info = (FAS216_Info *)instance->hostdata; + + outb(CMD_RESETCHIP, REG_CMD(info)); + queue_free (&info->queues.disconnected); + queue_free (&info->queues.issue); + + return 0; +} + +EXPORT_SYMBOL(fas216_init); +EXPORT_SYMBOL(fas216_abort); +EXPORT_SYMBOL(fas216_reset); +EXPORT_SYMBOL(fas216_queue_command); +EXPORT_SYMBOL(fas216_command); +EXPORT_SYMBOL(fas216_intr); +EXPORT_SYMBOL(fas216_release); + +#ifdef MODULE +int init_module (void) +{ + return 0; +} + +void cleanup_module (void) +{ +} +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/fas216.h new/linux/drivers/acorn/scsi/fas216.h --- old/linux/drivers/acorn/scsi/fas216.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/fas216.h Wed Feb 18 23:13:52 1998 @@ -0,0 +1,357 @@ +/* + * FAS216 generic driver + * + * Copyright (C) 1997-1998 Russell King + * + * NOTE! This file should be viewed using a console with + * >100 character width (since it uses 8-space tabs) + * (it used to fit in 80-columns with 4 space) + */ +#ifndef FAS216_H +#define FAS216_H + +#ifndef NO_IRQ +#define NO_IRQ 255 +#endif + +#include "queue.h" +#include "msgqueue.h" + +/* FAS register definitions */ + +/* transfer count low */ +#define REG_CTCL(x) ((x)->scsi.io_port) +#define REG_STCL(x) ((x)->scsi.io_port) + +/* transfer count medium */ +#define REG_CTCM(x) ((x)->scsi.io_port + (1 << (x)->scsi.io_shift)) +#define REG_STCM(x) ((x)->scsi.io_port + (1 << (x)->scsi.io_shift)) + +/* fifo data */ +#define REG_FF(x) ((x)->scsi.io_port + (2 << (x)->scsi.io_shift)) + +/* command */ +#define REG_CMD(x) ((x)->scsi.io_port + (3 << (x)->scsi.io_shift)) +#define CMD_NOP 0x00 +#define CMD_FLUSHFIFO 0x01 +#define CMD_RESETCHIP 0x02 +#define CMD_RESETSCSI 0x03 + +#define CMD_TRANSFERINFO 0x10 +#define CMD_INITCMDCOMPLETE 0x11 +#define CMD_MSGACCEPTED 0x12 +#define CMD_SETATN 0x1a +#define CMD_RSETATN 0x1b + +#define CMD_SELECTWOATN 0x41 +#define CMD_SELECTATN 0x42 +#define CMD_SELECTATNSTOP 0x43 +#define CMD_ENABLESEL 0x44 +#define CMD_DISABLESEL 0x45 +#define CMD_SELECTATN3 0x46 +#define CMD_RESEL3 0x47 + +#define CMD_WITHDMA 0x80 + +/* status register (read) */ +#define REG_STAT(x) ((x)->scsi.io_port + (4 << (x)->scsi.io_shift)) +#define STAT_IO (1 << 0) /* IO phase */ +#define STAT_CD (1 << 1) /* CD phase */ +#define STAT_MSG (1 << 2) /* MSG phase */ +#define STAT_TRANSFERDONE (1 << 3) /* Transfer completed */ +#define STAT_TRANSFERCNTZ (1 << 4) /* Transfer counter is zero */ +#define STAT_PARITYERROR (1 << 5) /* Parity error */ +#define STAT_REALBAD (1 << 6) /* Something bad */ +#define STAT_INT (1 << 7) /* Interrupt */ + +#define STAT_BUSMASK (STAT_MSG|STAT_CD|STAT_IO) +#define STAT_DATAOUT (0) /* Data out */ +#define STAT_DATAIN (STAT_IO) /* Data in */ +#define STAT_COMMAND (STAT_CD) /* Command out */ +#define STAT_STATUS (STAT_CD|STAT_IO) /* Status In */ +#define STAT_MESGOUT (STAT_MSG|STAT_CD) /* Message out */ +#define STAT_MESGIN (STAT_MSG|STAT_CD|STAT_IO) /* Message In */ + +/* bus ID for select / reselect */ +#define REG_SDID(x) ((x)->scsi.io_port + (4 << (x)->scsi.io_shift)) +#define BUSID(target) ((target) & 7) + +/* Interrupt status register (read) */ +#define REG_INST(x) ((x)->scsi.io_port + (5 << (x)->scsi.io_shift)) +#define INST_SELWOATN (1 << 0) /* Select w/o ATN */ +#define INST_SELATN (1 << 1) /* Select w/ATN */ +#define INST_RESELECTED (1 << 2) /* Reselected */ +#define INST_FUNCDONE (1 << 3) /* Function done */ +#define INST_BUSSERVICE (1 << 4) /* Bus service */ +#define INST_DISCONNECT (1 << 5) /* Disconnect */ +#define INST_ILLEGALCMD (1 << 6) /* Illegal command */ +#define INST_BUSRESET (1 << 7) /* SCSI Bus reset */ + +/* Timeout register (write) */ +#define REG_STIM(x) ((x)->scsi.io_port + (5 << (x)->scsi.io_shift)) + +/* Sequence step register (read) */ +#define REG_IS(x) ((x)->scsi.io_port + (6 << (x)->scsi.io_shift)) +#define IS_BITS 0x07 +#define IS_SELARB 0x00 /* Select & Arb ok */ +#define IS_MSGBYTESENT 0x01 /* One byte message sent*/ +#define IS_NOTCOMMAND 0x02 /* Not in command state */ +#define IS_EARLYPHASE 0x03 /* Early phase change */ +#define IS_COMPLETE 0x04 /* Command ok */ + +/* Transfer period step (write) */ +#define REG_STP(x) ((x)->scsi.io_port + (6 << (x)->scsi.io_shift)) + +/* Synchronous Offset (write) */ +#define REG_SOF(x) ((x)->scsi.io_port + (7 << (x)->scsi.io_shift)) + +/* Fifo state register (read) */ +#define REG_CFIS(x) ((x)->scsi.io_port + (7 << (x)->scsi.io_shift)) +#define CFIS_CF 0x1f /* Num bytes in FIFO */ +#define CFIS_IS 0xe0 /* Step */ + +/* config register 1 */ +#define REG_CNTL1(x) ((x)->scsi.io_port + (8 << (x)->scsi.io_shift)) +#define CNTL1_CID (7 << 0) /* Chip ID */ +#define CNTL1_STE (1 << 3) /* Self test enable */ +#define CNTL1_PERE (1 << 4) /* Parity enable reporting en. */ +#define CNTL1_PTE (1 << 5) /* Parity test enable */ +#define CNTL1_DISR (1 << 6) /* Disable Irq on SCSI reset */ +#define CNTL1_ETM (1 << 7) /* Extended Timing Mode */ + +/* Clock conversion factor (read) */ +#define REG_CLKF(x) ((x)->scsi.io_port + (9 << (x)->scsi.io_shift)) +#define CLKF_F37MHZ 0x00 /* 35.01 - 40 MHz */ +#define CLKF_F10MHZ 0x02 /* 10 MHz */ +#define CLKF_F12MHZ 0x03 /* 10.01 - 15 MHz */ +#define CLKF_F17MHZ 0x04 /* 15.01 - 20 MHz */ +#define CLKF_F22MHZ 0x05 /* 20.01 - 25 MHz */ +#define CLKF_F27MHZ 0x06 /* 25.01 - 30 MHz */ +#define CLKF_F32MHZ 0x07 /* 30.01 - 35 MHz */ + +/* Chip test register (write) */ +#define REG0_FTM(x) ((x)->scsi.io_port + (10 << (x)->scsi.io_shift)) +#define TEST_FTM 0x01 /* Force target mode */ +#define TEST_FIM 0x02 /* Force initiator mode */ +#define TEST_FHI 0x04 /* Force high impedance mode */ + +/* Configuration register 2 (read/write) */ +#define REG_CNTL2(x) ((x)->scsi.io_port + (11 << (x)->scsi.io_shift)) +#define CNTL2_PGDP (1 << 0) /* Pass Th/Generate Data Parity */ +#define CNTL2_PGRP (1 << 1) /* Pass Th/Generate Reg Parity */ +#define CNTL2_ACDPE (1 << 2) /* Abort on Cmd/Data Parity Err */ +#define CNTL2_S2FE (1 << 3) /* SCSI2 Features Enable */ +#define CNTL2_TSDR (1 << 4) /* Tristate DREQ */ +#define CNTL2_SBO (1 << 5) /* Select Byte Order */ +#define CNTL2_ENF (1 << 6) /* Enable features */ +#define CNTL2_DAE (1 << 7) /* Data Alignment Enable */ + +/* Configuration register 3 (read/write) */ +#define REG_CNTL3(x) ((x)->scsi.io_port + (12 << (x)->scsi.io_shift)) +#define CNTL3_BS8 (1 << 0) /* Burst size 8 */ +#define CNTL3_MDM (1 << 1) /* Modify DMA mode */ +#define CNTL3_LBTM (1 << 2) /* Last Byte Transfer mode */ +#define CNTL3_FASTCLK (1 << 3) /* Fast SCSI clocking */ +#define CNTL3_FASTSCSI (1 << 4) /* Fast SCSI */ +#define CNTL3_G2CB (1 << 5) /* Group2 SCSI support */ +#define CNTL3_QTAG (1 << 6) /* Enable 3 byte msgs */ +#define CNTL3_ADIDCHK (1 << 7) /* Additional ID check */ + +/* High transfer count (read/write) */ +#define REG_CTCH(x) ((x)->scsi.io_port + (14 << (x)->scsi.io_shift)) +#define REG_STCH(x) ((x)->scsi.io_port + (14 << (x)->scsi.io_shift)) + +/* ID reigster (read only) */ +#define REG1_ID(x) ((x)->scsi.io_port + (14 << (x)->scsi.io_shift)) + +/* Data alignment */ +#define REG0_DAL(x) ((x)->scsi.io_port + (15 << (x)->scsi.io_shift)) + +typedef enum { + PHASE_IDLE, /* we're not planning on doing anything */ + PHASE_SELECTION, /* selecting a device */ + PHASE_RECONNECTED, /* reconnected */ + PHASE_DATAOUT, /* data out to device */ + PHASE_DATAIN, /* data in from device */ + PHASE_MSGIN, /* message in from device */ + PHASE_MSGOUT, /* message out to device */ + PHASE_AFTERMSGOUT, /* after message out phase */ + PHASE_STATUS, /* status from device */ + PHASE_DISCONNECT, /* disconnecting from bus */ + PHASE_DONE /* Command complete */ +} phase_t; + +typedef enum { + DMA_OUT, /* DMA from memory to chip */ + DMA_IN /* DMA from chip to memory */ +} fasdmadir_t; + +typedef enum { + fasdma_none, /* No dma */ + fasdma_pseudo, /* Pseudo DMA */ + fasdma_real_block, /* Real DMA, on block by block basis */ + fasdma_real_all /* Real DMA, on request by request */ +} fasdmatype_t; + +typedef enum { + syncneg_start, /* Negociate with device for Sync xfers */ + syncneg_sent, /* Sync Xfer negociation sent */ + syncnsg_complete /* Sync Xfer complete */ +} syncneg_t; + +typedef struct { + struct Scsi_Host *host; /* host */ + Scsi_Cmnd *SCpnt; /* currently processing command */ + Scsi_Cmnd *origSCpnt; /* original connecting command */ + + /* driver information */ + struct { + unsigned int io_port; /* base address of FAS216 */ + unsigned int io_shift; /* shift to adjust reg offsets by */ + unsigned char irq; /* interrupt */ + unsigned char cfg[4]; /* configuration registers */ + const char *type; /* chip type */ + phase_t phase; /* current phase */ + + struct { + unsigned char target; /* reconnected target */ + unsigned char lun; /* reconnected lun */ + unsigned char tag; /* reconnected tag */ + } reconnected; + + Scsi_Pointer SCp; /* current commands data pointer */ + + MsgQueue_t msgs; /* message queue for connected device */ + + unsigned short last_message; /* last message to be sent */ + + unsigned char disconnectable:1; /* this command can be disconnected */ + unsigned char aborting:1; /* aborting command */ + } scsi; + + /* statistics information */ + struct { + unsigned int queues; + unsigned int removes; + unsigned int fins; + unsigned int reads; + unsigned int writes; + unsigned int miscs; + unsigned int disconnects; + unsigned int aborts; + unsigned int resets; + } stats; + + /* configuration information */ + struct { + unsigned char clockrate; /* clock rate of FAS device (MHz) */ + unsigned char select_timeout; /* timeout (R5) */ + unsigned int asyncperiod; /* Async transfer period (ns) */ + unsigned char sync_max_depth; /* Synchronous xfer max fifo depth */ + } ifcfg; + + /* queue handling */ + struct { + Queue_t issue; /* issue queue */ + Queue_t disconnected; /* disconnected command queue */ + } queues; + + /* per-device info */ + struct { + unsigned char disconnect_ok:1; /* device can disconnect */ + unsigned char stp; /* synchronous transfer period */ + unsigned char sof; /* synchronous offset register */ + syncneg_t negstate; /* synchronous transfer mode */ + } device[8]; + unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ + + /* dma */ + struct { + fasdmatype_t transfer_type; /* current type of DMA transfer */ + fasdmatype_t (*setup) (struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction); + int (*pseudo)(struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, int transfer); + void (*stop) (struct Scsi_Host *host, Scsi_Pointer *SCp); + } dma; + + /* miscellaneous */ + int internal_done; /* flag to indicate request done */ +} FAS216_Info; + +/* + * Function: int fas216_init (struct Scsi_Host *instance) + * + * Purpose : initialise FAS/NCR/AMD SCSI ic. + * + * Params : instance - a driver-specific filled-out structure + * + * Returns : 0 on success + */ +extern int fas216_init (struct Scsi_Host *instance); + +/* + * Function: int fas216_abort (Scsi_Cmnd *SCpnt) + * + * Purpose : abort a command if something horrible happens. + * + * Params : SCpnt - Command that is believed to be causing a problem. + * + * Returns : one of SCSI_ABORT_ macros. + */ +extern int fas216_abort (Scsi_Cmnd *); + +/* + * Function: int fas216_reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) + * + * Purpose : resets the adapter if something horrible happens. + * + * Params : SCpnt - Command that is believed to be causing a problem. + * reset_flags - flags indicating reset type that is believed to be required. + * + * Returns : one of SCSI_RESET_ macros, or'd with the SCSI_RESET_*_RESET macros. + */ +extern int fas216_reset (Scsi_Cmnd *, unsigned int); + +/* + * Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) + * + * Purpose : queue a command for adapter to process. + * + * Params : SCpnt - Command to queue + * done - done function to call once command is complete + * + * Returns : 0 - success, else error + */ +extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); + +/* + * Function: int fas216_command (Scsi_Cmnd *SCpnt) + * + * Purpose : queue a command for adapter to process. + * + * Params : SCpnt - Command to queue + * + * Returns : scsi result code + */ +extern int fas216_command (Scsi_Cmnd *); + +/* + * Function: void fas216_intr (struct Scsi_Host *instance) + * + * Purpose : handle interrupts from the interface to progress a command + * + * Params : instance - interface to service + */ +extern void fas216_intr (struct Scsi_Host *instance); + +/* + * Function: int fas216_release (struct Scsi_Host *instance) + * + * Purpose : release all resources and put everything to bed for FAS/NCR/AMD SCSI ic. + * + * Params : instance - a driver-specific filled-out structure + * + * Returns : 0 on success + */ +extern int fas216_release (struct Scsi_Host *instance); + +#endif /* FAS216_H */ diff -ur --new-file old/linux/drivers/acorn/scsi/msgqueue.c new/linux/drivers/acorn/scsi/msgqueue.c --- old/linux/drivers/acorn/scsi/msgqueue.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/msgqueue.c Sat Feb 7 16:17:46 1998 @@ -0,0 +1,175 @@ +/* + * drivers/acorn/scsi/msgqueue.c: message queue handling + * + * Copyright (C) 1997,8 Russell King + */ + +#include +#include +#include + +#include "msgqueue.h" + +/* + * Function: struct msgqueue_entry *mqe_alloc (MsgQueue_t *msgq) + * Purpose : Allocate a message queue entry + * Params : msgq - message queue to claim entry for + * Returns : message queue entry or NULL. + */ +static struct msgqueue_entry *mqe_alloc (MsgQueue_t *msgq) +{ + struct msgqueue_entry *mq; + + if ((mq = msgq->free) != NULL) + msgq->free = mq->next; + + return mq; +} + +/* + * Function: void mqe_free (MsgQueue_t *msgq, struct msgqueue_entry *mq) + * Purpose : free a message queue entry + * Params : msgq - message queue to free entry from + * mq - message queue entry to free + */ +static void mqe_free (MsgQueue_t *msgq, struct msgqueue_entry *mq) +{ + if (mq) { + mq->next = msgq->free; + msgq->free = mq; + } +} + +/* + * Function: void msgqueue_initialise (MsgQueue_t *msgq) + * Purpose : initialise a message queue + * Params : msgq - queue to initialise + */ +void msgqueue_initialise (MsgQueue_t *msgq) +{ + int i; + + msgq->qe = NULL; + msgq->free = &msgq->entries[0]; + + for (i = 0; i < NR_MESSAGES; i++) + msgq->entries[i].next = &msgq->entries[i + 1]; + + msgq->entries[NR_MESSAGES - 1].next = NULL; +} + + +/* + * Function: void msgqueue_free (MsgQueue_t *msgq) + * Purpose : free a queue + * Params : msgq - queue to free + */ +void msgqueue_free (MsgQueue_t *msgq) +{ +} + +/* + * Function: int msgqueue_msglength (MsgQueue_t *msgq) + * Purpose : calculate the total length of all messages on the message queue + * Params : msgq - queue to examine + * Returns : number of bytes of messages in queue + */ +int msgqueue_msglength (MsgQueue_t *msgq) +{ + struct msgqueue_entry *mq = msgq->qe; + int length = 0; + + for (mq = msgq->qe; mq; mq = mq->next) + length += mq->length; + + return length; +} + +/* + * Function: char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length) + * Purpose : return a message & its length + * Params : msgq - queue to obtain message from + * length - pointer to int for message length + * Returns : pointer to message string + */ +char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length) +{ + struct msgqueue_entry *mq; + + if ((mq = msgq->qe) != NULL) { + msgq->qe = mq->next; + mqe_free (msgq, mq); + *length = mq->length; + } + + return mq ? mq->msg : NULL; +} + +/* + * Function: int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...) + * Purpose : add a message onto a message queue + * Params : msgq - queue to add message on + * length - length of message + * ... - message bytes + * Returns : != 0 if successful + */ +int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...) +{ + struct msgqueue_entry *mq = mqe_alloc (msgq); + va_list ap; + + if (mq) { + struct msgqueue_entry **mqp; + int i; + + va_start (ap, length); + for (i = 0; i < length; i++) + mq->msg[i] = va_arg (ap, unsigned char); + va_end (ap); + + mq->length = length; + mq->next = NULL; + + mqp = &msgq->qe; + while (*mqp) + mqp = &(*mqp)->next; + + *mqp = mq; + } + + return mq != NULL; +} + +/* + * Function: void msgqueue_flush (MsgQueue_t *msgq) + * Purpose : flush all messages from message queue + * Params : msgq - queue to flush + */ +void msgqueue_flush (MsgQueue_t *msgq) +{ + struct msgqueue_entry *mq, *mqnext; + + for (mq = msgq->qe; mq; mq = mqnext) { + mqnext = mq->next; + mqe_free (msgq, mq); + } + msgq->qe = NULL; +} + +EXPORT_SYMBOL(msgqueue_initialise); +EXPORT_SYMBOL(msgqueue_free); +EXPORT_SYMBOL(msgqueue_msglength); +EXPORT_SYMBOL(msgqueue_getnextmsg); +EXPORT_SYMBOL(msgqueue_addmsg); +EXPORT_SYMBOL(msgqueue_flush); + +#ifdef MODULE +int init_module (void) +{ + return 0; +} + +void cleanup_module (void) +{ +} +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/msgqueue.h new/linux/drivers/acorn/scsi/msgqueue.h --- old/linux/drivers/acorn/scsi/msgqueue.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/msgqueue.h Sat Oct 4 18:14:47 1997 @@ -0,0 +1,71 @@ +/* + * msgqueue.h: message queue handling + * + * (c) 1997 Russell King + */ +#ifndef MSGQUEUE_H +#define MSGQUEUE_H + +struct msgqueue_entry { + char msg[8]; + int length; + struct msgqueue_entry *next; +}; + +#define NR_MESSAGES 4 + +typedef struct { + struct msgqueue_entry *qe; + struct msgqueue_entry *free; + struct msgqueue_entry entries[NR_MESSAGES]; +} MsgQueue_t; + +/* + * Function: void msgqueue_initialise (MsgQueue_t *msgq) + * Purpose : initialise a message queue + * Params : msgq - queue to initialise + */ +extern void msgqueue_initialise (MsgQueue_t *msgq); + +/* + * Function: void msgqueue_free (MsgQueue_t *msgq) + * Purpose : free a queue + * Params : msgq - queue to free + */ +extern void msgqueue_free (MsgQueue_t *msgq); + +/* + * Function: int msgqueue_msglength (MsgQueue_t *msgq) + * Purpose : calculate the total length of all messages on the message queue + * Params : msgq - queue to examine + * Returns : number of bytes of messages in queue + */ +extern int msgqueue_msglength (MsgQueue_t *msgq); + +/* + * Function: char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length) + * Purpose : return a message & its length + * Params : msgq - queue to obtain message from + * length - pointer to int for message length + * Returns : pointer to message string + */ +extern char *msgqueue_getnextmsg (MsgQueue_t *msgq, int *length); + +/* + * Function: int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...) + * Purpose : add a message onto a message queue + * Params : msgq - queue to add message on + * length - length of message + * ... - message bytes + * Returns : != 0 if successful + */ +extern int msgqueue_addmsg (MsgQueue_t *msgq, int length, ...); + +/* + * Function: void msgqueue_flush (MsgQueue_t *msgq) + * Purpose : flush all messages from message queue + * Params : msgq - queue to flush + */ +extern void msgqueue_flush (MsgQueue_t *msgq); + +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/oak.c new/linux/drivers/acorn/scsi/oak.c --- old/linux/drivers/acorn/scsi/oak.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/oak.c Sat Feb 21 22:25:15 1998 @@ -0,0 +1,227 @@ +#define AUTOSENSE +/*#define PSEUDO_DMA*/ + +/* + * Oak Generic NCR5380 driver + * + * Copyright 1995, Russell King + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * Options : + * + * PARITY - enable parity checking. Not supported. + * + * SCSI2 - enable support for SCSI-II tagged queueing. Untested. + * + * USLEEP - enable support for devices that don't disconnect. Untested. + */ + +/* + * $Log: oak.c,v $ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../../scsi/scsi.h" +#include "../../scsi/hosts.h" +#include "oak.h" +#include "../../scsi/NCR5380.h" +#include "../../scsi/constants.h" + +#undef START_DMA_INITIATOR_RECEIVE_REG +#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128) + +static const card_ids oakscsi_cids[] = { + { MANU_OAK, PROD_OAK_SCSI }, + { 0xffff, 0xffff } +}; + +static struct proc_dir_entry proc_scsi_oakscsi = { + PROC_SCSI_PAS16, 7, "oakscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +#define OAK_ADDRESS(card) (ecard_address((card), ECARD_MEMC, 0)) +#define OAK_IRQ(card) (IRQ_NONE) +/* + * Function : int oakscsi_detect(Scsi_Host_Template * tpnt) + * + * Purpose : initializes oak NCR5380 driver based on the + * command line / compile time port and irq definitions. + * + * Inputs : tpnt - template for this SCSI adapter. + * + * Returns : 1 if a host adapter was found, 0 if not. + * + */ +static struct expansion_card *ecs[4]; + +int oakscsi_detect(Scsi_Host_Template * tpnt) +{ + int count = 0; + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_oakscsi; + + memset (ecs, 0, sizeof (ecs)); + + ecard_startfind (); + + while(1) { + if ((ecs[count] = ecard_find(0, oakscsi_cids)) == NULL) + break; + + instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); + instance->io_port = OAK_ADDRESS(ecs[count]); + instance->irq = OAK_IRQ(ecs[count]); + + NCR5380_init(instance, 0); + ecard_claim(ecs[count]); + + instance->n_io_port = 255; + request_region (instance->io_port, instance->n_io_port, "Oak SCSI"); + + if (instance->irq != IRQ_NONE) + if (request_irq(instance->irq, oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) { + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = IRQ_NONE; + } + + if (instance->irq != IRQ_NONE) { + printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no); + printk("scsi%d: that the board had an interrupt!\n", instance->host_no); + } + + printk("scsi%d: at port %X irq", instance->host_no, instance->io_port); + if (instance->irq == IRQ_NONE) + printk ("s disabled"); + else + printk (" %d", instance->irq); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", + CAN_QUEUE, CMD_PER_LUN, OAKSCSI_PUBLIC_RELEASE); + printk("\nscsi%d:", instance->host_no); + NCR5380_print_options(instance); + printk("\n"); + + ++count; + } +#ifdef MODULE + if(count == 0) + printk("No oak scsi devices found\n"); +#endif + return count; +} + +int oakscsi_release (struct Scsi_Host *shpnt) +{ + int i; + + if (shpnt->irq != IRQ_NONE) + free_irq (shpnt->irq, NULL); + if (shpnt->io_port) + release_region (shpnt->io_port, shpnt->n_io_port); + + for (i = 0; i < 4; i++) + if (shpnt->io_port == OAK_ADDRESS(ecs[i])) + ecard_release (ecs[i]); + return 0; +} + +const char * oakscsi_info (struct Scsi_Host *spnt) { + return ""; +} + +#define STAT(p) inw(p + 144) +extern void inswb(int from, void *to, int len); + +static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int iobase = instance->io_port; +printk("writing %p len %d\n",addr, len); + if(!len) return -1; + + while(1) + { + int status; + while(((status = STAT(iobase)) & 0x100)==0); + } +} + +static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, + int len) +{ + int iobase = instance->io_port; +printk("reading %p len %d\n", addr, len); + while(len > 0) + { + int status, timeout; + unsigned long b; + + timeout = 0x01FFFFFF; + + while(((status = STAT(iobase)) & 0x100)==0) + { + timeout--; + if(status & 0x200 || !timeout) + { + printk("status = %08X\n",status); + return 1; + } + } + if(len >= 128) + { + inswb(iobase + 136, addr, 128); + addr += 128; + len -= 128; + } + else + { + b = (unsigned long) inw(iobase + 136); + *addr ++ = b; + len -= 1; + if(len) + *addr ++ = b>>8; + len -= 1; + } + } + return 0; +} + +#define oakscsi_read(instance,reg) (inb((instance)->io_port + (reg))) +#define oakscsi_write(instance,reg,val) (outb((val), (instance)->io_port + (reg))) + +#undef STAT + +#include "../../scsi/NCR5380.c" + +#ifdef MODULE + +Scsi_Host_Template driver_template = OAK_NCR5380; + +#include "../../scsi/scsi_module.c" +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/oak.h new/linux/drivers/acorn/scsi/oak.h --- old/linux/drivers/acorn/scsi/oak.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/oak.h Sun Dec 28 18:20:10 1997 @@ -0,0 +1,97 @@ +/* + * Cumana Generic NCR5380 driver defines + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 440-4894 + * + * ALPHA RELEASE 1. + * + * For more information, please consult + * + * NCR 5380 Family + * SCSI Protocol Controller + * Databook + * + * NCR Microelectronics + * 1635 Aeroplaza Drive + * Colorado Springs, CO 80916 + * 1+ (719) 578-3400 + * 1+ (800) 334-5454 + */ + +/* + * $Log: oak_NCR5380.h,v $ + */ + +#ifndef OAK_NCR5380_H +#define OAK_NCR5380_H + +#define OAKSCSI_PUBLIC_RELEASE 1 + + +#ifndef ASM +int oakscsi_abort(Scsi_Cmnd *); +int oakscsi_detect(Scsi_Host_Template *); +int oakscsi_release(struct Scsi_Host *); +const char *oakscsi_info(struct Scsi_Host *); +int oakscsi_reset(Scsi_Cmnd *, unsigned int); +int oakscsi_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int oakscsi_proc_info (char *buffer, char **start, off_t off, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#define OAK_NCR5380 { \ +proc_info: oakscsi_proc_info, \ +name: "Oak 16-bit SCSI", \ +detect: oakscsi_detect, \ +release: oakscsi_release, /* Release */ \ +info: oakscsi_info, \ +queuecommand: oakscsi_queue_command, \ +abort: oakscsi_abort, \ +reset: oakscsi_reset, \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: 7, /* id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ +use_clustering: DISABLE_CLUSTERING \ + } + +#ifndef HOSTS_C +#define NCR5380_implementation_fields \ + int port, ctrl + +#define NCR5380_local_declare() \ + struct Scsi_Host *_instance + +#define NCR5380_setup(instance) \ + _instance = instance + +#define NCR5380_read(reg) oakscsi_read(_instance, reg) +#define NCR5380_write(reg, value) oakscsi_write(_instance, reg, value) +#define NCR5380_intr oakscsi_intr +#define NCR5380_queue_command oakscsi_queue_command +#define NCR5380_abort oakscsi_abort +#define NCR5380_reset oakscsi_reset +#define NCR5380_proc_info oakscsi_proc_info + +#define BOARD_NORMAL 0 +#define BOARD_NCR53C400 1 + +#endif /* else def HOSTS_C */ +#endif /* ndef ASM */ +#endif /* OAK_NCR5380_H */ + diff -ur --new-file old/linux/drivers/acorn/scsi/powertec.c new/linux/drivers/acorn/scsi/powertec.c --- old/linux/drivers/acorn/scsi/powertec.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/powertec.c Wed Feb 18 23:55:07 1998 @@ -0,0 +1,410 @@ +/* + * linux/arch/arm/drivers/scsi/powertec.c + * + * Copyright (C) 1997 Russell King + * + * This driver is based on experimentation. Hence, it may have made + * assumptions about the particular card that I have available, and + * may not be reliable! + * + * Changelog: + * 01-10-1997 RMK Created, READONLY version + * 15-02-1998 RMK Added DMA support and hardware definitions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../../scsi/sd.h" +#include "../../scsi/hosts.h" +#include "powertec.h" + +/* Configuration */ +#define POWERTEC_XTALFREQ 40 +#define POWERTEC_ASYNC_PERIOD 200 +#define POWERTEC_SYNC_DEPTH 16 + +/* + * List of devices that the driver will recognise + */ +#define POWERTECSCSI_LIST { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI } + +#define POWERTEC_FAS216_OFFSET 0xc00 +#define POWERTEC_FAS216_SHIFT 4 +#define POWERTEC_INTR_STATUS 0x800 +#define POWERTEC_INTR_BIT 0x80 +#define POWERTEC_INTR_CONTROL 0x407 +#define POWERTEC_INTR_ENABLE 1 +#define POWERTEC_INTR_DISABLE 0 + +/* + * Version + */ +#define VER_MAJOR 0 +#define VER_MINOR 0 +#define VER_PATCH 1 + +static struct expansion_card *ecs[MAX_ECARDS]; + +static struct proc_dir_entry proc_scsi_powertec = { + PROC_SCSI_QLOGICISP, 8, "powertec", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +/* Function: void powertecscsi_irqenable(ec, irqnr) + * Purpose : Enable interrupts on powertec SCSI card + * Params : ec - expansion card structure + * : irqnr - interrupt number + */ +static void +powertecscsi_irqenable(struct expansion_card *ec, int irqnr) +{ + unsigned int port = (unsigned int)ec->irq_data; + outb(POWERTEC_INTR_ENABLE, port); +} + +/* Function: void powertecscsi_irqdisable(ec, irqnr) + * Purpose : Disable interrupts on powertec SCSI card + * Params : ec - expansion card structure + * : irqnr - interrupt number + */ +static void +powertecscsi_irqdisable(struct expansion_card *ec, int irqnr) +{ + unsigned int port = (unsigned int)ec->irq_data; + outb(POWERTEC_INTR_DISABLE, port); +} + +static const expansioncard_ops_t powertecscsi_ops = { + powertecscsi_irqenable, + powertecscsi_irqdisable, + NULL, + NULL +}; + +/* Function: void powertecscsi_intr(int irq, void *dev_id, + * struct pt_regs *regs) + * Purpose : handle interrupts from Powertec SCSI card + * Params : irq - interrupt number + * dev_id - user-defined (Scsi_Host structure) + * regs - processor registers at interrupt + */ +static void +powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct Scsi_Host *instance = (struct Scsi_Host *)dev_id; + + fas216_intr(instance); +} + +static void +powertecscsi_invalidate(char *addr, long len, fasdmadir_t direction) +{ + unsigned int page; + + if (direction == DMA_OUT) { + for (page = (unsigned int) addr; len > 0; + page += PAGE_SIZE, len -= PAGE_SIZE) + flush_page_to_ram(page); + } else + flush_cache_range(current->mm, (unsigned long)addr, + (unsigned long)addr + len); +} + +/* Function: fasdmatype_t powertecscsi_dma_setup(instance, SCpnt, direction) + * Purpose : initialises DMA/PIO + * Params : instance - host + * SCpnt - command + * direction - DMA on to/off of card + * Returns : type of transfer to be performed + */ +static fasdmatype_t +powertecscsi_dma_setup(struct Scsi_Host *instance, Scsi_Pointer *SCp, + fasdmadir_t direction) +{ + if (instance->dma_channel != NO_DMA && SCp->this_residual >= 512) { + int buf; +static dmasg_t dmasg[256]; + + for (buf = 1; buf <= SCp->buffers_residual; buf++) { + dmasg[buf].address = __virt_to_bus( + (unsigned long)SCp->buffer[buf].address); + dmasg[buf].length = SCp->buffer[buf].length; + + powertecscsi_invalidate(SCp->buffer[buf].address, + SCp->buffer[buf].length, + direction); + } + + dmasg[0].address = __virt_to_phys((unsigned long)SCp->ptr); + dmasg[0].length = SCp->this_residual; + powertecscsi_invalidate(SCp->ptr, + SCp->this_residual, direction); + + disable_dma(instance->dma_channel); + set_dma_sg(instance->dma_channel, dmasg, buf); + set_dma_mode(instance->dma_channel, + direction == DMA_OUT ? DMA_MODE_WRITE : + DMA_MODE_READ); + enable_dma(instance->dma_channel); + return fasdma_real_all; + } + /* + * We don't do DMA, we only do slow PIO + */ + return fasdma_none; +} + +/* Function: int powertecscsi_dma_stop(instance, SCpnt) + * Purpose : stops DMA/PIO + * Params : instance - host + * SCpnt - command + */ +static void +powertecscsi_dma_stop(struct Scsi_Host *instance, Scsi_Pointer *SCp) +{ + if (instance->dma_channel != NO_DMA) + disable_dma(instance->dma_channel); +} + +/* Function: int powertecscsi_detect(Scsi_Host_Template * tpnt) + * Purpose : initialises PowerTec SCSI driver + * Params : tpnt - template for this SCSI adapter + * Returns : >0 if host found, 0 otherwise. + */ +int +powertecscsi_detect(Scsi_Host_Template *tpnt) +{ + static const card_ids powertecscsi_cids[] = + { POWERTECSCSI_LIST, { 0xffff, 0xffff} }; + int count = 0; + struct Scsi_Host *instance; + + tpnt->proc_dir = &proc_scsi_powertec; + memset(ecs, 0, sizeof (ecs)); + + ecard_startfind(); + + while(1) { + PowerTecScsi_Info *info; + + ecs[count] = ecard_find(0, powertecscsi_cids); + if (!ecs[count]) + break; + + ecard_claim(ecs[count]); + + instance = scsi_register(tpnt, sizeof (PowerTecScsi_Info)); + if (!instance) { + ecard_release(ecs[count]); + break; + } + + instance->io_port = ecard_address(ecs[count], ECARD_IOC, 0); + instance->irq = ecs[count]->irq; + + ecs[count]->irqaddr = (unsigned char *) + ioaddr(instance->io_port + POWERTEC_INTR_STATUS); + ecs[count]->irqmask = POWERTEC_INTR_BIT; + ecs[count]->irq_data = (void *) + (instance->io_port + POWERTEC_INTR_CONTROL); + ecs[count]->ops = (expansioncard_ops_t *)&powertecscsi_ops; + + request_region(instance->io_port + POWERTEC_FAS216_OFFSET, + 16 << POWERTEC_FAS216_SHIFT, "powertec2-fas"); + + if (request_irq(instance->irq, powertecscsi_intr, + SA_INTERRUPT, "powertec", instance)) { + printk("scsi%d: IRQ%d not free, interrupts disabled\n", + instance->host_no, instance->irq); + instance->irq = NO_IRQ; + } + + info = (PowerTecScsi_Info *)instance->hostdata; + + instance->dma_channel = 3; /* slot 1 */ + if (request_dma(instance->dma_channel, "powertec")) { + printk("scsi%d: DMA%d not free, DMA disabled\n", + instance->host_no, instance->dma_channel); + instance->dma_channel = NO_DMA; + } + + info->info.scsi.io_port = + instance->io_port + POWERTEC_FAS216_OFFSET; + info->info.scsi.io_shift= POWERTEC_FAS216_SHIFT; + info->info.scsi.irq = instance->irq; + info->info.ifcfg.clockrate = POWERTEC_XTALFREQ; + info->info.ifcfg.select_timeout = 255; + info->info.ifcfg.asyncperiod = POWERTEC_ASYNC_PERIOD; + info->info.ifcfg.sync_max_depth = POWERTEC_SYNC_DEPTH; + info->info.dma.setup = powertecscsi_dma_setup; + info->info.dma.pseudo = NULL; + info->info.dma.stop = powertecscsi_dma_stop; + + fas216_init(instance); + ++count; + } + return count; +} + +/* Function: int powertecscsi_release(struct Scsi_Host * host) + * Purpose : releases all resources used by this adapter + * Params : host - driver host structure to return info for. + * Returns : nothing + */ +int powertecscsi_release(struct Scsi_Host *instance) +{ + int i; + + fas216_release(instance); + + if (instance->irq != NO_IRQ) + free_irq(instance->irq, instance); + if (instance->dma_channel != NO_DMA) + free_dma(instance->dma_channel); + release_region(instance->io_port + POWERTEC_FAS216_OFFSET, + 16 << POWERTEC_FAS216_SHIFT); + + for (i = 0; i < MAX_ECARDS; i++) + if (ecs[i] && + instance->io_port == ecard_address(ecs[i], ECARD_IOC, 0)) + ecard_release(ecs[i]); + return 0; +} + +/* Function: const char *powertecscsi_info(struct Scsi_Host * host) + * Purpose : returns a descriptive string about this interface, + * Params : host - driver host structure to return info for. + * Returns : pointer to a static buffer containing null terminated string. + */ +const char *powertecscsi_info(struct Scsi_Host *host) +{ + PowerTecScsi_Info *info = (PowerTecScsi_Info *)host->hostdata; + static char string[100], *p; + + p = string; + p += sprintf(string, "%s at port %X ", + host->hostt->name, host->io_port); + + if (host->irq != NO_IRQ) + p += sprintf(p, "irq %d ", host->irq); + else + p += sprintf(p, "NO IRQ "); + + if (host->dma_channel != NO_DMA) + p += sprintf(p, "dma %d ", host->dma_channel); + else + p += sprintf(p, "NO DMA "); + + p += sprintf(p, "v%d.%d.%d scsi %s", + VER_MAJOR, VER_MINOR, VER_PATCH, + info->info.scsi.type); + + return string; +} + +/* Function: int powertecscsi_proc_info(char *buffer, char **start, off_t offset, + * int length, int host_no, int inout) + * Purpose : Return information about the driver to a user process accessing + * the /proc filesystem. + * Params : buffer - a buffer to write information to + * start - a pointer into this buffer set by this routine to the start + * of the required information. + * offset - offset into information that we have read upto. + * length - length of buffer + * host_no - host number to return information for + * inout - 0 for reading, 1 for writing. + * Returns : length of data written to buffer. + */ +int powertecscsi_proc_info(char *buffer, char **start, off_t offset, + int length, int host_no, int inout) +{ + int pos, begin; + struct Scsi_Host *host = scsi_hostlist; + PowerTecScsi_Info *info; + Scsi_Device *scd; + + while (host) { + if (host->host_no == host_no) + break; + host = host->next; + } + if (!host) + return 0; + + info = (PowerTecScsi_Info *)host->hostdata; + if (inout == 1) + return -EINVAL; + + begin = 0; + pos = sprintf(buffer, + "PowerTec SCSI driver version %d.%d.%d\n", + VER_MAJOR, VER_MINOR, VER_PATCH); + pos += sprintf(buffer + pos, + "Address: %08X IRQ : %d DMA : %d\n" + "FAS : %s\n\n" + "Statistics:\n", + host->io_port, host->irq, host->dma_channel, + info->info.scsi.type); + + pos += sprintf(buffer+pos, + "Queued commands: %-10d Issued commands: %-10d\n" + "Done commands : %-10d Reads : %-10d\n" + "Writes : %-10d Others : %-10d\n" + "Disconnects : %-10d Aborts : %-10d\n" + "Resets : %-10d\n", + info->info.stats.queues, info->info.stats.removes, + info->info.stats.fins, info->info.stats.reads, + info->info.stats.writes, info->info.stats.miscs, + info->info.stats.disconnects, info->info.stats.aborts, + info->info.stats.resets); + + pos += sprintf (buffer+pos, "\nAttached devices:%s\n", host->host_queue ? "" : " none"); + + for (scd = host->host_queue; scd; scd = scd->next) { + int len; + + proc_print_scsidevice (scd, buffer, &len, pos); + pos += len; + pos += sprintf (buffer+pos, "Extensions: "); + if (scd->tagged_supported) + pos += sprintf (buffer+pos, "TAG %sabled [%d] ", + scd->tagged_queue ? "en" : "dis", + scd->current_tag); + pos += sprintf (buffer+pos, "\n"); + + if (pos + begin < offset) { + begin += pos; + pos = 0; + } + if (pos + begin > offset + length) + break; + } + + *start = buffer + (offset - begin); + pos -= offset - begin; + if (pos > length) + pos = length; + + return pos; +} + +#ifdef MODULE +Scsi_Host_Template driver_template = POWERTECSCSI; + +#include "../../scsi/scsi_module.c" +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/powertec.h new/linux/drivers/acorn/scsi/powertec.h --- old/linux/drivers/acorn/scsi/powertec.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/powertec.h Sun Feb 15 16:56:11 1998 @@ -0,0 +1,69 @@ +/* + * PowerTec SCSI driver + * + * Copyright (C) 1997 Russell King + */ +#ifndef POWERTECSCSI_H +#define POWERTECSCSI_H + +extern int powertecscsi_detect (Scsi_Host_Template *); +extern int powertecscsi_release (struct Scsi_Host *); +extern const char *powertecscsi_info (struct Scsi_Host *); +extern int powertecscsi_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout); + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef CAN_QUEUE +/* + * Default queue size + */ +#define CAN_QUEUE 1 +#endif + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 1 +#endif + +#ifndef SCSI_ID +/* + * Default SCSI host ID + */ +#define SCSI_ID 7 +#endif + +#include + +#include "fas216.h" + +#define POWERTECSCSI { \ +proc_info: powertecscsi_proc_info, \ +name: "PowerTec SCSI", \ +detect: powertecscsi_detect, /* detect */ \ +release: powertecscsi_release, /* release */ \ +info: powertecscsi_info, /* info */ \ +command: fas216_command, /* command */ \ +queuecommand: fas216_queue_command, /* queuecommand */ \ +abort: fas216_abort, /* abort */ \ +reset: fas216_reset, /* reset */ \ +bios_param: scsicam_bios_param, /* biosparam */ \ +can_queue: CAN_QUEUE, /* can queue */ \ +this_id: SCSI_ID, /* scsi host id */ \ +sg_tablesize: SG_ALL, /* sg_tablesize */ \ +cmd_per_lun: CMD_PER_LUN, /* cmd per lun */ \ +use_clustering: ENABLE_CLUSTERING \ + } + +#ifndef HOSTS_C + +typedef struct { + FAS216_Info info; + + /* other info... */ +} PowerTecScsi_Info; + +#endif /* HOSTS_C */ + +#endif /* POWERTECSCSI_H */ diff -ur --new-file old/linux/drivers/acorn/scsi/queue.c new/linux/drivers/acorn/scsi/queue.c --- old/linux/drivers/acorn/scsi/queue.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/queue.c Sat Feb 7 16:15:19 1998 @@ -0,0 +1,432 @@ +/* + * queue.c: queue handling primitives + * + * (c) 1997 Russell King + * + * Changelog: + * 15-Sep-1997 RMK Created. + * 11-Oct-1997 RMK Corrected problem with queue_remove_exclude + * not updating internal linked list properly + * (was causing commands to go missing). + */ + +#define SECTOR_SIZE 512 + +#include +#include +#include +#include +#include + +#include "../../scsi/scsi.h" + +typedef struct queue_entry { + struct queue_entry *next; + struct queue_entry *prev; + unsigned long magic; + Scsi_Cmnd *SCpnt; +} QE_t; + +#define QUEUE_MAGIC_FREE 0xf7e1c9a3 +#define QUEUE_MAGIC_USED 0xf7e1cc33 + +#include "queue.h" + +/* + * Function: void queue_initialise (Queue_t *queue) + * Purpose : initialise a queue + * Params : queue - queue to initialise + */ +int queue_initialise (Queue_t *queue) +{ + unsigned int nqueues; + QE_t *q; + + queue->alloc = queue->free = q = (QE_t *) kmalloc (SECTOR_SIZE, GFP_KERNEL); + if (q) { + nqueues = SECTOR_SIZE / sizeof (QE_t); + + for (; nqueues; q++, nqueues--) { + q->next = q + 1; + q->prev = NULL; + q->magic = QUEUE_MAGIC_FREE; + q->SCpnt = NULL; + } + q->next = NULL; + } + + return q != NULL; +} + +/* + * Function: void queue_free (Queue_t *queue) + * Purpose : free a queue + * Params : queue - queue to free + */ +void queue_free (Queue_t *queue) +{ + if (queue->alloc) + kfree (queue->alloc); +} + + +/* + * Function: int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head. + * Params : queue - destination queue + * SCpnt - command to add + * Returns : 0 on error, !0 on success + */ +int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt) +{ + unsigned long flags; + QE_t *q; + + save_flags_cli (flags); + q = queue->free; + if (q) + queue->free = q->next; + + if (q) { + if (q->magic != QUEUE_MAGIC_FREE) { + restore_flags (flags); + panic ("scsi queues corrupted - queue entry not free"); + } + + q->magic = QUEUE_MAGIC_USED; + q->SCpnt = SCpnt; + + if (SCpnt->cmnd[0] == REQUEST_SENSE) { /* request_sense gets put on the queue head */ + if (queue->head) { + q->prev = NULL; + q->next = queue->head; + queue->head->prev = q; + queue->head = q; + } else { + q->next = q->prev = NULL; + queue->head = queue->tail = q; + } + } else { /* others get put on the tail */ + if (queue->tail) { + q->next = NULL; + q->prev = queue->tail; + queue->tail->next = q; + queue->tail = q; + } else { + q->next = q->prev = NULL; + queue->head = queue->tail = q; + } + } + } + restore_flags (flags); + + return q != NULL; +} + +/* + * Function: int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : Add a new command onto a queue, adding onto tail of list + * Params : queue - destination queue + * SCpnt - command to add + * Returns : 0 on error, !0 on success + */ +int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt) +{ + unsigned long flags; + QE_t *q; + + save_flags_cli (flags); + q = queue->free; + if (q) + queue->free = q->next; + + if (q) { + if (q->magic != QUEUE_MAGIC_FREE) { + restore_flags (flags); + panic ("scsi queues corrupted - queue entry not free"); + } + + q->magic = QUEUE_MAGIC_USED; + q->SCpnt = SCpnt; + + if (queue->tail) { + q->next = NULL; + q->prev = queue->tail; + queue->tail->next = q; + queue->tail = q; + } else { + q->next = q->prev = NULL; + queue->head = queue->tail = q; + } + } + restore_flags (flags); + + return q != NULL; +} + +/* + * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude) + * Purpose : remove a SCSI command from a queue + * Params : queue - queue to remove command from + * exclude - bit array of target&lun which is busy + * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + */ +Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned char *exclude) +{ + unsigned long flags; + Scsi_Cmnd *SCpnt; + QE_t *q, *prev; + + save_flags_cli (flags); + for (q = queue->head, prev = NULL; q; q = q->next) { + if (exclude && !test_bit (q->SCpnt->target * 8 + q->SCpnt->lun, exclude)) + break; + prev = q; + } + + if (q) { + if (q->magic != QUEUE_MAGIC_USED) { + restore_flags (flags); + panic ("q_remove_exclude: scsi queues corrupted - queue entry not used"); + } + if (q->prev != prev) + panic ("q_remove_exclude: scsi queues corrupted - q->prev != prev"); + + if (!prev) { + queue->head = q->next; + if (queue->head) + queue->head->prev = NULL; + else + queue->tail = NULL; + } else { + prev->next = q->next; + if (prev->next) + prev->next->prev = prev; + else + queue->tail = prev; + } + + SCpnt = q->SCpnt; + + q->next = queue->free; + queue->free = q; + q->magic = QUEUE_MAGIC_FREE; + } else + SCpnt = NULL; + + restore_flags (flags); + + return SCpnt; +} + +/* + * Function: Scsi_Cmnd *queue_remove (queue) + * Purpose : removes first SCSI command from a queue + * Params : queue - queue to remove command from + * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + */ +Scsi_Cmnd *queue_remove (Queue_t *queue) +{ + unsigned long flags; + Scsi_Cmnd *SCpnt; + QE_t *q; + + save_flags_cli (flags); + q = queue->head; + if (q) { + queue->head = q->next; + if (queue->head) + queue->head->prev = NULL; + else + queue->tail = NULL; + + if (q->magic != QUEUE_MAGIC_USED) { + restore_flags (flags); + panic ("scsi queues corrupted - queue entry not used"); + } + + SCpnt = q->SCpnt; + + q->next = queue->free; + queue->free = q; + q->magic = QUEUE_MAGIC_FREE; + } else + SCpnt = NULL; + + restore_flags (flags); + + return SCpnt; +} + +/* + * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag) + * Purpose : remove a SCSI command from the queue for a specified target/lun/tag + * Params : queue - queue to remove command from + * target - target that we want + * lun - lun on device + * tag - tag on device + * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements + */ +Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag) +{ + unsigned long flags; + Scsi_Cmnd *SCpnt; + QE_t *q, *prev; + + save_flags_cli (flags); + for (q = queue->head, prev = NULL; q; q = q->next) { + if (q->SCpnt->target == target && + q->SCpnt->lun == lun && + q->SCpnt->tag == tag) + break; + + prev = q; + } + + if (q) { + if (q->magic != QUEUE_MAGIC_USED) { + restore_flags (flags); + panic ("q_remove_tgtluntag: scsi queues corrupted - queue entry not used"); + } + if (q->prev != prev) + panic ("q_remove_tgtluntag: scsi queues corrupted - q->prev != prev"); + + if (!prev) { + queue->head = q->next; + if (queue->head) + queue->head->prev = NULL; + else + queue->tail = NULL; + } else { + prev->next = q->next; + if (prev->next) + prev->next->prev = prev; + else + queue->tail = prev; + } + + SCpnt = q->SCpnt; + + q->magic = QUEUE_MAGIC_FREE; + q->next = queue->free; + queue->free = q; + } else + SCpnt = NULL; + + restore_flags (flags); + + return SCpnt; +} + +/* + * Function: int queue_probetgtlun (queue, target, lun) + * Purpose : check to see if we have a command in the queue for the specified + * target/lun. + * Params : queue - queue to look in + * target - target we want to probe + * lun - lun on target + * Returns : 0 if not found, != 0 if found + */ +int queue_probetgtlun (Queue_t *queue, int target, int lun) +{ + QE_t *q; + + for (q = queue->head; q; q = q->next) + if (q->SCpnt->target == target && + q->SCpnt->lun == lun) + break; + + return q != NULL; +} + +/* + * Function: int queue_cmdonqueue (queue, SCpnt) + * Purpose : check to see if we have a command on the queue + * Params : queue - queue to look in + * SCpnt - command to find + * Returns : 0 if not found, != 0 if found + */ +int queue_cmdonqueue (Queue_t *queue, Scsi_Cmnd *SCpnt) +{ + QE_t *q; + + for (q = queue->head; q; q = q->next) + if (q->SCpnt == SCpnt) + break; + + return q != NULL; +} + +/* + * Function: int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : remove a specific command from the queues + * Params : queue - queue to look in + * SCpnt - command to find + * Returns : 0 if not found + */ +int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt) +{ + unsigned long flags; + QE_t *q, *prev; + + save_flags_cli (flags); + for (q = queue->head, prev = NULL; q; q = q->next) { + if (q->SCpnt == SCpnt) + break; + + prev = q; + } + + if (q) { + if (q->magic != QUEUE_MAGIC_USED) { + restore_flags (flags); + panic ("q_removecmd: scsi queues corrupted - queue entry not used"); + } + if (q->prev != prev) + panic ("q_removecmd: scsi queues corrupted - q->prev != prev"); + + if (!prev) { + queue->head = q->next; + if (queue->head) + queue->head->prev = NULL; + else + queue->tail = NULL; + } else { + prev->next = q->next; + if (prev->next) + prev->next->prev = prev; + else + queue->tail = prev; + } + + q->magic = QUEUE_MAGIC_FREE; + q->next = queue->free; + queue->free = q; + } + + restore_flags (flags); + + return q != NULL; +} + +EXPORT_SYMBOL(queue_initialise); +EXPORT_SYMBOL(queue_free); +EXPORT_SYMBOL(queue_remove); +EXPORT_SYMBOL(queue_remove_exclude); +EXPORT_SYMBOL(queue_add_cmd_ordered); +EXPORT_SYMBOL(queue_add_cmd_tail); +EXPORT_SYMBOL(queue_remove_tgtluntag); +EXPORT_SYMBOL(queue_probetgtlun); +EXPORT_SYMBOL(queue_cmdonqueue); +EXPORT_SYMBOL(queue_removecmd); + +#ifdef MODULE +int init_module (void) +{ + return 0; +} + +void cleanup_module (void) +{ +} +#endif diff -ur --new-file old/linux/drivers/acorn/scsi/queue.h new/linux/drivers/acorn/scsi/queue.h --- old/linux/drivers/acorn/scsi/queue.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/acorn/scsi/queue.h Thu Sep 25 23:35:09 1997 @@ -0,0 +1,106 @@ +/* + * queue.h: queue handling + * + * (c) 1997 Russell King + */ +#ifndef QUEUE_H +#define QUEUE_H + +typedef struct { + struct queue_entry *head; /* head of queue */ + struct queue_entry *tail; /* tail of queue */ + struct queue_entry *free; /* free list */ + void *alloc; /* start of allocated mem */ +} Queue_t; + +/* + * Function: void queue_initialise (Queue_t *queue) + * Purpose : initialise a queue + * Params : queue - queue to initialise + */ +extern int queue_initialise (Queue_t *queue); + +/* + * Function: void queue_free (Queue_t *queue) + * Purpose : free a queue + * Params : queue - queue to free + */ +extern void queue_free (Queue_t *queue); + +/* + * Function: Scsi_Cmnd *queue_remove (queue) + * Purpose : removes first SCSI command from a queue + * Params : queue - queue to remove command from + * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + */ +extern Scsi_Cmnd *queue_remove (Queue_t *queue); + +/* + * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude, ref) + * Purpose : remove a SCSI command from a queue + * Params : queue - queue to remove command from + * exclude - array of busy LUNs + * ref - a reference that can be used to put the command back + * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available + */ +extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned char *exclude); + +/* + * Function: int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : Add a new command onto a queue, queueing REQUEST_SENSE first + * Params : queue - destination queue + * SCpnt - command to add + * Returns : 0 on error, !0 on success + */ +extern int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt); + +/* + * Function: int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : Add a new command onto a queue, queueing at end of list + * Params : queue - destination queue + * SCpnt - command to add + * Returns : 0 on error, !0 on success + */ +extern int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt); + +/* + * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag) + * Purpose : remove a SCSI command from the queue for a specified target/lun/tag + * Params : queue - queue to remove command from + * target - target that we want + * lun - lun on device + * tag - tag on device + * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements + */ +extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag); + +/* + * Function: int queue_probetgtlun (queue, target, lun) + * Purpose : check to see if we have a command in the queue for the specified + * target/lun. + * Params : queue - queue to look in + * target - target we want to probe + * lun - lun on target + * Returns : 0 if not found, != 0 if found + */ +extern int queue_probetgtlun (Queue_t *queue, int target, int lun); + +/* + * Function: int queue_cmdonqueue (queue, SCpnt) + * Purpose : check to see if we have a command on the queue + * Params : queue - queue to look in + * SCpnt - command to find + * Returns : 0 if not found, != 0 if found + */ +int queue_cmdonqueue (Queue_t *queue, Scsi_Cmnd *SCpnt); + +/* + * Function: int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Purpose : remove a specific command from the queues + * Params : queue - queue to look in + * SCpnt - command to find + * Returns : 0 if not found + */ +int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt); + +#endif /* QUEUE_H */ diff -ur --new-file old/linux/drivers/ap1000/bif.c new/linux/drivers/ap1000/bif.c --- old/linux/drivers/ap1000/bif.c Fri Feb 7 14:54:54 1997 +++ new/linux/drivers/ap1000/bif.c Tue Feb 10 22:07:50 1998 @@ -242,7 +242,7 @@ if (bif_device == NULL) { printk("bif: bif_device is NULL in bif_rx\n"); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } skb->dev = bif_device; diff -ur --new-file old/linux/drivers/ap1000/ddv.c new/linux/drivers/ap1000/ddv.c --- old/linux/drivers/ap1000/ddv.c Sun Jan 4 19:40:15 1998 +++ new/linux/drivers/ap1000/ddv.c Sat Feb 21 03:28:22 1998 @@ -14,7 +14,6 @@ */ #include -#include #include #include #include diff -ur --new-file old/linux/drivers/ap1000/mac.c new/linux/drivers/ap1000/mac.c --- old/linux/drivers/ap1000/mac.c Sun Jan 26 11:07:10 1997 +++ new/linux/drivers/ap1000/mac.c Tue Feb 10 22:07:50 1998 @@ -803,7 +803,7 @@ memcpy(msp->cur_mbuf.ptr - 3, el->skb->data, ROUND4(el->skb->len)); mac_queue_frame((struct mac_buf *)&msp->cur_mbuf); - dev_kfree_skb(el->skb, FREE_WRITE); + dev_kfree_skb(el->skb); kfree_s(el, sizeof(*el)); continue; } @@ -1096,7 +1096,7 @@ printk("mac_dma_complete(): Calling mac_queue_frame\n"); #endif mac_queue_frame((struct mac_buf *)&msp->cur_mbuf); - dev_kfree_skb(msp->cur_macq->skb, FREE_WRITE); + dev_kfree_skb(msp->cur_macq->skb); kfree_s((struct mac_buf *)msp->cur_macq, sizeof(*(msp->cur_macq))); msp->cur_macq = NULL; #if MAC_DEBUG diff -ur --new-file old/linux/drivers/ap1000/ringbuf.c new/linux/drivers/ap1000/ringbuf.c --- old/linux/drivers/ap1000/ringbuf.c Tue Jun 17 01:35:54 1997 +++ new/linux/drivers/ap1000/ringbuf.c Sat Jan 17 05:38:21 1998 @@ -49,7 +49,7 @@ /* preallocate some ringbuffers */ for (i=0;idev->dev_data; if (!out_vcc) { if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb,FREE_WRITE); + else dev_kfree_skb(skb); vcc->stats->tx_err++; return -ENOLINK; } @@ -85,7 +85,7 @@ } if (!new_skb) { if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb,FREE_WRITE); + else dev_kfree_skb(skb); vcc->stats->tx_err++; return -ENOBUFS; } @@ -95,7 +95,7 @@ hdr->length = htonl(skb->len); memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb,FREE_WRITE); + else dev_kfree_skb(skb); out_vcc->push(out_vcc,new_skb); return 0; } @@ -126,7 +126,7 @@ break; if (!out_vcc) { if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb,FREE_WRITE); + else dev_kfree_skb(skb); vcc->stats->tx_err++; return 0; } @@ -138,12 +138,12 @@ } if (!new_skb) { if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb,FREE_WRITE); + else dev_kfree_skb(skb); return -ENOBUFS; } memcpy(skb_put(new_skb,skb->len),skb->data,skb->len); if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb,FREE_WRITE); + else dev_kfree_skb(skb); out_vcc->push(out_vcc,new_skb); return 0; } diff -ur --new-file old/linux/drivers/atm/eni.c new/linux/drivers/atm/eni.c --- old/linux/drivers/atm/eni.c Fri Mar 27 02:41:48 1998 +++ new/linux/drivers/atm/eni.c Fri Mar 27 02:42:25 1998 @@ -411,7 +411,7 @@ } if (!j || j > 2*RX_DMA_BUF) { printk(KERN_CRIT DEV_LABEL "!j or j too big!!!\n"); - if (skb) kfree_skb(skb,FREE_READ); + if (skb) kfree_skb(skb); return -1; } dma[j-2] |= MID_DMA_END; @@ -425,7 +425,7 @@ if (!NEPMOK(dma_wr,j+j+1,dma_rd,NR_DMA_RX)) { /* @@@ +1 is ugly */ printk(KERN_WARNING DEV_LABEL "(itf %d): RX DMA full\n", vcc->dev->number); - if (skb) kfree_skb(skb,FREE_READ); + if (skb) kfree_skb(skb); return -1; } for (i = 0; i < j; i++) { @@ -723,7 +723,7 @@ } eni_vcc->rxing--; eni_vcc->rx_pos = skb->atm.pos & (eni_vcc->words-1); - if (!skb->len) kfree_skb(skb,FREE_READ); + if (!skb->len) kfree_skb(skb); else { EVENT("pushing (len=%ld)\n",skb->len,0); if (vcc->qos.aal == ATM_AAL0) @@ -1123,7 +1123,7 @@ } ENI_VCC(vcc)->txing -= skb->atm.size; if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb,FREE_WRITE); + else dev_kfree_skb(skb); vcc->stats->tx++; wake_up(&eni_dev->tx_wait); dma_complete++; @@ -1946,17 +1946,17 @@ DPRINTK(">eni_send\n"); if (!ENI_VCC(vcc)->tx) { - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); return -EINVAL; } if (!skb) { printk(KERN_CRIT "!skb in eni_send ?\n"); - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); return -EINVAL; } if (vcc->qos.aal == ATM_AAL0) { if (skb->len != ATM_CELL_SIZE-1) { - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); return -EINVAL; } *(unsigned long *) skb->data = htonl(*(unsigned long *) diff -ur --new-file old/linux/drivers/atm/zatm.c new/linux/drivers/atm/zatm.c --- old/linux/drivers/atm/zatm.c Fri Mar 27 02:41:48 1998 +++ new/linux/drivers/atm/zatm.c Fri Mar 27 02:42:25 1998 @@ -253,8 +253,7 @@ { struct sk_buff *skb; - while ((skb = skb_dequeue(&ZATM_DEV(dev)->pool[pool]))) - kfree_skb(skb,FREE_READ); + while ((skb = skb_dequeue(&ZATM_DEV(dev)->pool[pool]))) kfree_skb(skb); } @@ -635,12 +634,12 @@ event_dump(); } if (!size) { - kfree_skb(skb,FREE_READ); + kfree_skb(skb); if (vcc) vcc->stats->rx_err++; continue; } if (!atm_charge(vcc,skb->truesize)) { - kfree_skb(skb,FREE_READ); + kfree_skb(skb); continue; } skb->len = size; @@ -852,7 +851,7 @@ dsc = (u32 *) kmalloc(uPD98401_TXPD_SIZE*2+ uPD98401_TXBD_SIZE*skb->atm.iovcnt,GFP_ATOMIC); if (!dsc) { - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); return -EAGAIN; } /* @@@ should check alignment */ @@ -902,7 +901,7 @@ *(u32 *) skb->atm.pos = 0; /* mark as invalid */ zatm_vcc->txing--; if (vcc->pop) vcc->pop(vcc,skb); - else dev_kfree_skb(skb,FREE_WRITE); + else dev_kfree_skb(skb); while ((skb = skb_dequeue(&zatm_vcc->backlog))) if (do_tx(skb) == RING_BUSY) { skb_queue_head(&zatm_vcc->backlog,skb); @@ -1746,12 +1745,12 @@ EVENT(">zatm_send 0x%lx\n",(unsigned long) skb,0); if (!ZATM_VCC(vcc)->tx_chan || !(vcc->flags & ATM_VF_READY)) { - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); return -EINVAL; } if (!skb) { printk(KERN_CRIT "!skb in zatm_send ?\n"); - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); return -EINVAL; } skb->atm.vcc = vcc; diff -ur --new-file old/linux/drivers/block/Config.in new/linux/drivers/block/Config.in --- old/linux/drivers/block/Config.in Thu Jan 1 01:42:56 1998 +++ new/linux/drivers/block/Config.in Mon Feb 2 22:07:47 1998 @@ -65,19 +65,26 @@ tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 fi +if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then + bool ' Boot support (linear, striped)' CONFIG_MD_BOOT +fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD fi tristate 'XT harddisk support' CONFIG_BLK_DEV_XD +# PARIDE doesn't need PARPORT, but if PARPORT is configured as a module, +# PARIDE must also be a module. The bogus CONFIG_PARIDE_PARPORT option +# controls the choices given to the user ... + if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "n" ] ; then define_bool CONFIG_PARIDE_PARPORT y else define_bool CONFIG_PARIDE_PARPORT m fi dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARIDE_PARPORT -if [ "$CONFIG_PARIDE" != "n" ]; then +if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then source drivers/block/paride/Config.in fi diff -ur --new-file old/linux/drivers/block/Makefile new/linux/drivers/block/Makefile --- old/linux/drivers/block/Makefile Sun Dec 28 21:05:44 1997 +++ new/linux/drivers/block/Makefile Fri Mar 6 19:48:00 1998 @@ -20,10 +20,10 @@ L_TARGET := block.a -L_OBJS := ll_rw_blk.o genhd.o +L_OBJS := genhd.o M_OBJS := MOD_LIST_NAME := BLOCK_MODULES -LX_OBJS := +LX_OBJS := ll_rw_blk.o MX_OBJS := ifeq ($(CONFIG_MAC_FLOPPY),y) @@ -90,11 +90,12 @@ L_OBJS += ide-probe.o else ifeq ($(CONFIG_BLK_DEV_IDE),m) - MX_OBJS += ide.o + MIX_OBJS += ide.o ifeq ($(CONFIG_PROC_FS),y) M_OBJS += ide-proc.o endif - M_OBJS += ide-probe.o + M_OBJS += ide-mod.o + MX_OBJS += ide-probe.o endif endif @@ -118,7 +119,6 @@ L_OBJS += ps2esdi.o endif - ifeq ($(CONFIG_BLK_DEV_DTC2278),y) L_OBJS += dtc2278.o endif @@ -250,3 +250,6 @@ endif include $(TOPDIR)/Rules.make + +ide-mod.o: ide.o ide-proc.o + $(LD) $(LD_RFLAG) -r -o $@ ide.o ide-proc.o diff -ur --new-file old/linux/drivers/block/acsi.c new/linux/drivers/block/acsi.c --- old/linux/drivers/block/acsi.c Sun Jan 4 19:40:15 1998 +++ new/linux/drivers/block/acsi.c Sat Feb 21 02:55:45 1998 @@ -59,8 +59,11 @@ #include #include #include - #include +#include /* for SCSI_IOCTL_GET_IDLUN */ +typedef void Scsi_Device; /* hack to avoid including scsi.h */ +#include +#include /* for HDIO_GETGEO */ #include #include @@ -70,7 +73,7 @@ #include #include #include -#include +#include #define DEBUG @@ -386,7 +389,7 @@ #ifdef CONFIG_ATARI_SLM -extern void attach_slm( int target, int lun ); +extern int attach_slm( int target, int lun ); extern int slm_init( void ); #endif @@ -1121,12 +1124,30 @@ if (dev >= NDevices) return -EINVAL; switch (cmd) { - /* I left out the GETGEO cmd; This doesn't make much sense for - * ACSI disks... - */ + case HDIO_GETGEO: + /* HDIO_GETGEO is supported more for getting the partition's start + * sector... */ + { struct hd_geometry *geo = (struct hd_geometry *)arg; + /* just fake some geometry here, it's nonsense anyway; to make it + * easy, use Adaptec's usual 64/32 mapping */ + put_user( 64, &geo->heads ); + put_user( 32, &geo->sectors ); + put_user( acsi_info[dev].size >> 11, &geo->cylinders ); + put_user( acsi_part[MINOR(inode->i_rdev)].start_sect, &geo->start ); + return 0; + } + + case SCSI_IOCTL_GET_IDLUN: + /* SCSI compatible GET_IDLUN call to get target's ID and LUN number */ + put_user( acsi_info[dev].target | (acsi_info[dev].lun << 8), + &((Scsi_Idlun *) arg)->dev_id ); + put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id ); + return 0; + case BLKGETSIZE: /* Return device size */ return put_user(acsi_part[MINOR(inode->i_rdev)].nr_sects, (long *) arg); + case BLKFLSBUF: if(!suser()) return -EACCES; if(!inode->i_rdev) return -EINVAL; @@ -1784,8 +1805,8 @@ return -EBUSY; } - if (!(acsi_buffer = (char *)__get_free_pages(GFP_KERNEL, - ACSI_BUFFER_ORDER, 1))) { + if (!(acsi_buffer = + (char *)atari_stram_alloc( ACSI_BUFFER_SIZE, NULL, "acsi" ))) { printk( KERN_ERR "Unable to get ACSI ST-Ram buffer.\n" ); unregister_blkdev( MAJOR_NR, "ad" ); return -ENOMEM; @@ -1824,14 +1845,17 @@ del_timer( &acsi_timer ); blk_dev[MAJOR_NR].request_fn = 0; - free_pages( (unsigned long)acsi_buffer, ACSI_BUFFER_ORDER ); + atari_stram_free( acsi_buffer ); if (unregister_blkdev( MAJOR_NR, "ad" ) != 0) printk( KERN_ERR "acsi: cleanup_module failed\n"); + for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) if (*gdp == &acsi_gendisk) break; - if (*gdp) + if (!*gdp) + printk( KERN_ERR "acsi: entry in disk chain missing!\n" ); + else *gdp = (*gdp)->next; } #endif @@ -1861,7 +1885,7 @@ static int revalidate_acsidisk( int dev, int maxusage ) { - int device, major; + int device; struct gendisk * gdev; int max_p, start, i; struct acsi_info_struct *aip; @@ -1880,14 +1904,19 @@ max_p = gdev->max_p; start = device << gdev->minor_shift; - major = MAJOR_NR << 8; for( i = max_p - 1; i >= 0 ; i-- ) { - sync_dev( major | start | i ); - invalidate_inodes( major | start | i ); - invalidate_buffers( major | start | i ); + if (gdev->part[start + i].nr_sects != 0) { + kdev_t devp = MKDEV(MAJOR_NR, start + i); + struct super_block *sb = get_super(devp); + + fsync_dev(devp); + if (sb) + invalidate_inodes(sb); + invalidate_buffers(devp); + gdev->part[start + i].nr_sects = 0; + } gdev->part[start+i].start_sect = 0; - gdev->part[start+i].nr_sects = 0; }; stdma_lock( NULL, NULL ); diff -ur --new-file old/linux/drivers/block/acsi_slm.c new/linux/drivers/block/acsi_slm.c --- old/linux/drivers/block/acsi_slm.c Sat Sep 20 23:51:54 1997 +++ new/linux/drivers/block/acsi_slm.c Sat Feb 21 02:55:45 1998 @@ -73,6 +73,7 @@ #include #include #include +#include #include @@ -252,15 +253,15 @@ static char *slm_errstr( int stat ); static int slm_getstats( char *buffer, int device ); -static long slm_read( struct inode *node, struct file* file, char *buf, - unsigned long count ); +static ssize_t slm_read( struct file* file, char *buf, size_t count, loff_t + *ppos ); static void start_print( int device ); static void slm_interrupt(int irc, void *data, struct pt_regs *fp); static void slm_test_ready( unsigned long dummy ); static void set_dma_addr( unsigned long paddr ); static unsigned long get_dma_addr( void ); -static long slm_write( struct inode *node, struct file *file, const char *buf, - unsigned long count ); +static ssize_t slm_write( struct file *file, const char *buf, size_t count, + loff_t *ppos ); static int slm_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg ); static int slm_open( struct inode *inode, struct file *file ); @@ -372,10 +373,12 @@ } -static long slm_read( struct inode *node, struct file* file, - char *buf, unsigned long count ) +static ssize_t slm_read( struct file *file, char *buf, size_t count, + loff_t *ppos ) -{ unsigned long page; +{ + struct inode *node = file->f_dentry->d_inode; + unsigned long page; int length; int end; @@ -625,10 +628,12 @@ } -static long slm_write( struct inode *node, struct file *file, - const char *buf, unsigned long count ) +static ssize_t slm_write( struct file *file, const char *buf, size_t count, + loff_t *ppos ) -{ int device = MINOR( node->i_rdev ); +{ + struct inode *node = file->f_dentry->d_inode; + int device = MINOR( node->i_rdev ); int n, filled, w, h; while( SLMState == PRINTING || @@ -1005,7 +1010,7 @@ return -EBUSY; } - if (!(SLMBuffer = kmalloc( SLM_BUFFER_SIZE, GFP_KERNEL | GFP_DMA))) { + if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, NULL, "SLM" ))) { printk( KERN_ERR "Unable to get SLM ST-Ram buffer.\n" ); unregister_chrdev( MAJOR_NR, "slm" ); return -ENOMEM; @@ -1037,5 +1042,6 @@ { if (unregister_chrdev( MAJOR_NR, "slm" ) != 0) printk( KERN_ERR "acsi_slm: cleanup_module failed\n"); + atari_stram_free( SLMBuffer ); } #endif diff -ur --new-file old/linux/drivers/block/amiflop.c new/linux/drivers/block/amiflop.c --- old/linux/drivers/block/amiflop.c Wed May 14 07:41:04 1997 +++ new/linux/drivers/block/amiflop.c Sat Feb 21 02:55:45 1998 @@ -219,8 +219,8 @@ static int probing = 0; /* Prevent "aliased" accesses. */ -static fd_ref[4] = { 0,0,0,0 }; -static fd_device[4] = { 0,0,0,0 }; +static int fd_ref[4] = { 0,0,0,0 }; +static int fd_device[4] = { 0,0,0,0 }; /* * Current device number. Taken either from the block header or from the @@ -678,7 +678,7 @@ static void amiga_write(int disk, unsigned long raw, unsigned char *data, int track) { - int cnt; + unsigned int cnt; unsigned long *ptr = (unsigned long *)raw; disk&=3; @@ -1376,8 +1376,8 @@ static void redo_fd_request(void) { - unsigned int block, track, sector; - int device, drive, cnt; + unsigned int cnt, block, track, sector; + int device, drive; struct amiga_floppy_struct *floppy; char *data; unsigned long flags; @@ -1511,7 +1511,7 @@ { int drive = inode->i_rdev & 3; static struct floppy_struct getprm; - int error; + struct super_block * sb; unsigned long flags; switch(cmd){ @@ -1522,9 +1522,9 @@ loc.sectors = unit[drive].sects; loc.cylinders = unit[drive].type->tracks; loc.start = 0; - if ((error = copy_to_user((void *)param, (void *)&loc, - sizeof(struct hd_geometry)))) - return error; + if (copy_to_user((void *)param, (void *)&loc, + sizeof(struct hd_geometry))) + return -EFAULT; break; } case FDFMTBEG: @@ -1566,7 +1566,9 @@ break; case FDFMTEND: floppy_off(drive); - invalidate_inodes(inode->i_rdev); + sb = get_super(inode->i_rdev); + if (sb) + invalidate_inodes(sb); invalidate_buffers(inode->i_rdev); break; case FDGETPRM: @@ -1575,15 +1577,13 @@ getprm.head=unit[drive].type->heads; getprm.sect=unit[drive].sects; getprm.size=unit[drive].blocks; - if ((error = copy_to_user((void *)param, - (void *)&getprm, - sizeof(struct floppy_struct)))) - return error; + if (copy_to_user((void *)param, + (void *)&getprm, + sizeof(struct floppy_struct))) + return -EFAULT; break; case BLKGETSIZE: - if (put_user(unit[drive].blocks,(long *)param)) - return -EFAULT; - break; + return put_user(unit[drive].blocks,(long *)param); case FDSETPRM: case FDDEFPRM: return -EINVAL; @@ -1600,10 +1600,9 @@ break; #ifdef RAW_IOCTL case IOCTL_RAW_TRACK: - error = copy_to_user((void *)param, raw_buf, - unit[drive].type->read_size); - if (error) - return error; + if (copy_to_user((void *)param, raw_buf, + unit[drive].type->read_size)) + return -EFAULT; else return unit[drive].type->read_size; #endif @@ -1691,6 +1690,7 @@ if (type >= num_dr_types) { printk(KERN_WARNING "fd_probe: unsupported drive type %08lx found\n", code); + unit[drive].type = &drive_types[num_dr_types-1]; /* FD_NODRIVE */ return; } @@ -1795,9 +1795,12 @@ static int floppy_release(struct inode * inode, struct file * filp) { unsigned long flags; + struct super_block * sb; fsync_dev(inode->i_rdev); - invalidate_inodes(inode->i_rdev); + sb = get_super(inode->i_rdev); + if (sb) + invalidate_inodes(sb); invalidate_buffers(inode->i_rdev); save_flags (flags); cli(); @@ -1819,10 +1822,10 @@ return 0; } -void amiga_floppy_setup (char *str, int *ints) +__initfunc(void amiga_floppy_setup (char *str, int *ints)) { -printk ("amiflop: Setting default df0 to %x\n", ints[1]); -fd_def_df0 = ints[1]; + printk ("amiflop: Setting default df0 to %x\n", ints[1]); + fd_def_df0 = ints[1]; } static struct file_operations floppy_fops = { diff -ur --new-file old/linux/drivers/block/ataflop.c new/linux/drivers/block/ataflop.c --- old/linux/drivers/block/ataflop.c Sun Sep 21 19:46:52 1997 +++ new/linux/drivers/block/ataflop.c Sat Feb 21 02:55:45 1998 @@ -89,6 +89,7 @@ #include #include #include +#include #define MAJOR_NR FLOPPY_MAJOR #include @@ -278,7 +279,6 @@ 15*512, 30*512, 60*512 }; -#define MAX_SECTORS (MaxSectors[DriveType]) #define BUFFER_SIZE (BufferSize[DriveType]) unsigned char *DMABuffer; /* buffer for writes */ @@ -395,6 +395,7 @@ static void fd_rwsec( void ); static void fd_readtrack_check( unsigned long dummy ); static void fd_rwsec_done( int status ); +static void fd_rwsec_done1(int status); static void fd_writetrack( void ); static void fd_writetrack_done( int status ); static void fd_times_out( unsigned long dummy ); @@ -459,6 +460,7 @@ sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ tmp = sound_ym.rd_data_reg_sel; sound_ym.wd_data = (tmp | DSKDRVNONE) & ~(drive == 0 ? DSKDRV0 : DSKDRV1); + atari_dont_touch_floppy_select = 1; restore_flags(flags); /* restore track register to saved value */ @@ -482,8 +484,12 @@ save_flags(flags); cli(); /* protect against various other ints mucking around with the PSG */ + atari_dont_touch_floppy_select = 0; sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */ - sound_ym.wd_data = sound_ym.rd_data_reg_sel | 7; /* no drives selected */ + sound_ym.wd_data = (sound_ym.rd_data_reg_sel | + (MACH_IS_FALCON ? 3 : 7)); /* no drives selected */ + /* On Falcon, the drive B select line is used on the printer port, so + * leave it alone... */ SelectedDrive = -1; restore_flags(flags); } @@ -977,11 +983,12 @@ * search for the first non-existent sector and need 1 sec to * recognise that it isn't present :-( */ + del_timer (&readtrack_timer); readtrack_timer.expires = jiffies + HZ/5 + (old_motoron ? 0 : HZ); /* 1 rot. + 5 rot.s if motor was off */ - add_timer( &readtrack_timer ); MultReadInProgress = 1; + add_timer( &readtrack_timer ); } START_TIMEOUT(); } @@ -1028,6 +1035,7 @@ * the read operation */ SET_IRQ_HANDLER( NULL ); + MultReadInProgress = 0; restore_flags(flags); DPRINT(("fd_readtrack_check(): done\n")); FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI ); @@ -1036,7 +1044,7 @@ /* No error until now -- the FDC would have interrupted * otherwise! */ - fd_rwsec_done( 0 ); + fd_rwsec_done1(0); } else { /* not yet finished, wait another tenth rotation */ @@ -1050,19 +1058,23 @@ static void fd_rwsec_done( int status ) { - unsigned int track; - DPRINT(("fd_rwsec_done()\n")); - STOP_TIMEOUT(); - if (read_track) { + del_timer(&readtrack_timer); if (!MultReadInProgress) return; MultReadInProgress = 0; - del_timer( &readtrack_timer ); } + fd_rwsec_done1(status); +} +static void fd_rwsec_done1(int status) +{ + unsigned int track; + + STOP_TIMEOUT(); + /* Correct the track if stretch != 0 */ if (SUDT->stretch) { track = FDC_READ( FDCREG_TRACK); @@ -1147,7 +1159,7 @@ if (!ATARIHW_PRESENT( EXTD_DMA )) copy_buffer (addr, ReqData); } else { - dma_cache_maintenance( PhysTrackBuffer, MAX_SECTORS * 512, 0 ); + dma_cache_maintenance( PhysTrackBuffer, MaxSectors[DriveType] * 512, 0 ); BufferDrive = SelectedDrive; BufferSide = ReqSide; BufferTrack = ReqTrack; @@ -1802,7 +1814,7 @@ UD.steprate = FDCSTEP_12; break; default: /* should be -1 for "not set by user" */ - if (ATARIHW_PRESENT( FDCSPEED ) || is_medusa) + if (ATARIHW_PRESENT( FDCSPEED ) || MACH_IS_MEDUSA) UD.steprate = FDCSTEP_3; else UD.steprate = FDCSTEP_6; @@ -1827,7 +1839,7 @@ unsigned char status; int ok; - if (drive > 1) return( 0 ); + if (drive >= (MACH_IS_FALCON ? 1 : 2)) return( 0 ); fd_select_drive( drive ); /* disable interrupt temporarily */ @@ -2019,6 +2031,14 @@ { int i; + if (!MACH_IS_ATARI) + /* Amiga, Mac, ... don't have Atari-compatible floppy :-) */ + return -ENXIO; + + if (MACH_IS_HADES) + /* Hades doesn't have Atari-compatible floppy */ + return -ENXIO; + if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { printk(KERN_ERR "Unable to get major %d for floppy\n",MAJOR_NR); return -EBUSY; @@ -2029,7 +2049,7 @@ track buffering off for all Medusas, though it could be used with ones that have a counter card. But the test is too hard :-( */ - UseTrackbuffer = !is_medusa; + UseTrackbuffer = !MACH_IS_MEDUSA; /* initialize variables */ SelectedDrive = -1; @@ -2039,7 +2059,7 @@ timer_table[FLOPPY_TIMER].fn = check_change; timer_active &= ~(1 << FLOPPY_TIMER); - DMABuffer = kmalloc(BUFFER_SIZE + 512, GFP_KERNEL | GFP_DMA); + DMABuffer = atari_stram_alloc( BUFFER_SIZE+512, NULL, "ataflop" ); if (!DMABuffer) { printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n"); unregister_blkdev(MAJOR_NR, "fd"); @@ -2071,6 +2091,7 @@ UseTrackbuffer ? "" : "no "); config_types(); + (void)do_floppy; /* avoid warning about unused variable */ return 0; } @@ -2118,7 +2139,7 @@ blk_dev[MAJOR_NR].request_fn = 0; timer_active &= ~(1 << FLOPPY_TIMER); timer_table[FLOPPY_TIMER].fn = 0; - kfree (DMABuffer); + atari_stram_free( DMABuffer ); } #endif diff -ur --new-file old/linux/drivers/block/floppy.c new/linux/drivers/block/floppy.c --- old/linux/drivers/block/floppy.c Mon Jan 12 23:57:50 1998 +++ new/linux/drivers/block/floppy.c Thu Mar 12 00:25:12 1998 @@ -534,6 +534,8 @@ static unsigned char current_drive = 0; static long current_count_sectors = 0; static unsigned char sector_t; /* sector in track */ +static unsigned char in_sector_offset; /* offset within physical sector, + * expressed in units of 512 bytes */ #ifndef fd_eject #define fd_eject(x) -EINVAL @@ -1710,10 +1712,11 @@ } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2); } if (handler) { - if(softirq_trylock()) { + int cpu = smp_processor_id(); + if(softirq_trylock(cpu)) { /* got the lock, call the handler immediately */ handler(); - softirq_endlock(); + softirq_endlock(cpu); } else /* we interrupted a bottom half. Defer handler */ schedule_bh( (void *)(void *) handler); @@ -2082,7 +2085,7 @@ #define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2) #define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80) >>1)) -#define CT(x) ((x) | 0x40) +#define CT(x) ((x) | 0xc0) static void setup_format_params(int track) { struct fparm { @@ -2250,7 +2253,7 @@ /* Interrupt handler evaluating the result of the r/w operation */ static void rw_interrupt(void) { - int nr_sectors, ssize, eoc; + int nr_sectors, ssize, eoc, heads; if (!DRS->first_read_date) DRS->first_read_date = jiffies; @@ -2262,23 +2265,32 @@ eoc = 1; else eoc = 0; - nr_sectors = ((R_TRACK-TRACK)*_floppy->head+R_HEAD-HEAD) * - _floppy->sect + ((R_SECTOR-SECTOR+eoc) << SIZECODE >> 2) - - (sector_t % _floppy->sect) % ssize; + + if(COMMAND & 0x80) + heads = 2; + else + heads = 1; + + nr_sectors = (((R_TRACK-TRACK) * heads + + R_HEAD-HEAD) * SECT_PER_TRACK + + R_SECTOR-SECTOR + eoc) << SIZECODE >> 2; #ifdef FLOPPY_SANITY_CHECK - if (nr_sectors > current_count_sectors + ssize - - (current_count_sectors + sector_t) % ssize + - sector_t % ssize){ + if (nr_sectors / ssize > + (in_sector_offset + current_count_sectors + ssize - 1)/ssize) { DPRINT("long rw: %x instead of %lx\n", nr_sectors, current_count_sectors); printk("rs=%d s=%d\n", R_SECTOR, SECTOR); printk("rh=%d h=%d\n", R_HEAD, HEAD); printk("rt=%d t=%d\n", R_TRACK, TRACK); - printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK, - sector_t, ssize); + printk("heads=%d eoc=%d\n", heads, eoc); + printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK, + sector_t, ssize); + printk("in_sector_offset=%d\n", in_sector_offset); } #endif + + nr_sectors -= in_sector_offset; INFBOUND(nr_sectors,0); SUPBOUND(current_count_sectors, nr_sectors); @@ -2464,6 +2476,32 @@ } #endif +/* work around a bug in pseudo DMA + * (on some FDCs) pseudo DMA does not stop when the CPU stops + * sending data. Hence we need a different way to signal the + * transfer length: We use SECT_PER_TRACK. Unfortunately, this + * does not work with MT, hence we can only transfer one head at + * a time + */ +static void virtualdmabug_workaround(void) { + int hard_sectors, end_sector; + if(CT(COMMAND) == FD_WRITE) { + COMMAND &= ~0x80; /* switch off multiple track mode */ + + hard_sectors = raw_cmd->length >> (7 + SIZECODE); + end_sector = SECTOR + hard_sectors - 1; +#ifdef FLOPPY_SANITY_CHECK + if(end_sector > SECT_PER_TRACK) { + printk("too many sectors %d > %d\n", + end_sector, SECT_PER_TRACK); + return; + } +#endif + SECT_PER_TRACK = end_sector; /* make sure SECT_PER_TRACK points + * to end of transfer */ + } +} + /* * Formulate a read/write request. * this routine decides where to load the data (directly to buffer, or to @@ -2540,11 +2578,17 @@ CODE2SIZE; SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE; SECTOR = ((sector_t % _floppy->sect) << 2 >> SIZECODE) + 1; + + /* tracksize describes the size which can be filled up with sectors + * of size ssize. + */ tracksize = _floppy->sect - _floppy->sect % ssize; if (tracksize < _floppy->sect){ SECT_PER_TRACK ++; if (tracksize <= sector_t % _floppy->sect) SECTOR--; + + /* if we are beyond tracksize, fill up using smaller sectors */ while (tracksize <= sector_t % _floppy->sect){ while(tracksize + ssize > _floppy->sect){ SIZECODE--; @@ -2554,10 +2598,15 @@ tracksize += ssize; } max_sector = HEAD * _floppy->sect + tracksize; - } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) + } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) { max_sector = _floppy->sect; + } else if (!HEAD && CT(COMMAND) == FD_WRITE) { + /* for virtual DMA bug workaround */ + max_sector = _floppy->sect; + } - aligned_sector_t = sector_t - (sector_t % _floppy->sect) % ssize; + in_sector_offset = (sector_t % _floppy->sect) % ssize; + aligned_sector_t = sector_t - in_sector_offset; max_size = CURRENT->nr_sectors; if ((raw_cmd->track == buffer_track) && (current_drive == buffer_drive) && @@ -2567,7 +2616,7 @@ copy_buffer(1, max_sector, buffer_max); return 1; } - } else if (aligned_sector_t != sector_t || CURRENT->nr_sectors < ssize){ + } else if (in_sector_offset || CURRENT->nr_sectors < ssize){ if (CT(COMMAND) == FD_WRITE){ if (sector_t + CURRENT->nr_sectors > ssize && sector_t + CURRENT->nr_sectors < ssize + ssize) @@ -2624,6 +2673,8 @@ /* check_dma_crossing(raw_cmd->kernel_data, raw_cmd->length, "end of make_raw_request [1]");*/ + + virtualdmabug_workaround(); return 2; } } @@ -2637,7 +2688,7 @@ sector_t > buffer_max || sector_t < buffer_min || ((CT(COMMAND) == FD_READ || - (aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize))&& + (!in_sector_offset && CURRENT->nr_sectors >= ssize))&& max_sector > 2 * max_buffer_sectors + buffer_min && max_size + sector_t > 2 * max_buffer_sectors + buffer_min) /* not enough space */){ @@ -2654,7 +2705,7 @@ * is either aligned or the data already in the buffer * (buffer will be overwritten) */ #ifdef FLOPPY_SANITY_CHECK - if (sector_t != aligned_sector_t && buffer_track == -1) + if (in_sector_offset && buffer_track == -1) DPRINT("internal error offset !=0 on write\n"); #endif buffer_track = raw_cmd->track; @@ -2665,7 +2716,7 @@ 2*max_buffer_sectors+buffer_min-aligned_sector_t); /* round up current_count_sectors to get dma xfer size */ - raw_cmd->length = sector_t+current_count_sectors-aligned_sector_t; + raw_cmd->length = in_sector_offset+current_count_sectors; raw_cmd->length = ((raw_cmd->length -1)|(ssize-1))+1; raw_cmd->length <<= 9; #ifdef FLOPPY_SANITY_CHECK @@ -2729,6 +2780,8 @@ return 0; } #endif + + virtualdmabug_workaround(); return 2; } diff -ur --new-file old/linux/drivers/block/genhd.c new/linux/drivers/block/genhd.c --- old/linux/drivers/block/genhd.c Fri Mar 27 02:41:49 1998 +++ new/linux/drivers/block/genhd.c Fri Mar 27 02:42:25 1998 @@ -281,7 +281,7 @@ for(i=0; iv_slice[i]; - if (s->s_tag == 0) + if (s->s_size == 0) continue; printk(" [s%d]", i); /* solaris partitions are relative to current MS-DOS @@ -777,7 +777,9 @@ int blk, blocks_in_map; int dev_bsize, dev_pos, pos; unsigned secsize; +#ifdef CONFIG_PMAC int first_bootable = 1; +#endif struct mac_partition *part; struct mac_driver_desc *md; @@ -1093,6 +1095,9 @@ #ifdef CONFIG_PARPORT extern int parport_init(void); #endif +#ifdef CONFIG_MD_BOOT + extern void md_setup_drive(void) __init; +#endif struct gendisk *p; int nr=0; @@ -1125,5 +1130,8 @@ else #endif rd_load(); +#endif +#ifdef CONFIG_MD_BOOT + md_setup_drive(); #endif } 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 Sat Jan 10 19:42:55 1998 +++ new/linux/drivers/block/ide-cd.c Wed Mar 18 06:39:11 1998 @@ -3,13 +3,14 @@ * linux/drivers/block/ide-cd.c * Copyright (C) 1994, 1995, 1996 scott snyder * Copyright (C) 1996-1998 Erik Andersen + * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * * ATAPI CD-ROM driver. To be used with ide.c. * See Documentation/cdrom/ide-cd for usage information. * - * Suggestions are welcome. Patches that work are more welcome though. + * Suggestions are welcome. Patches that work are more welcome though. ;-) * For those wishing to work on this driver, please be sure you download * and comply with the latest ATAPI standard. This document can be * obtained by anonymous ftp from fission.dt.wdc.com in directory: @@ -25,7 +26,6 @@ * (If you are using a cd changer, you may get errors in the kernel * logs that are completly expected. Don't complain to me about this, * unless you have a patch to fix it. I am working on it...) - * -Implement ide_cdrom_select_speed using the generic cdrom interface * -Fix ide_cdrom_reset so that it works (it does nothing right now) * -Query the drive to find what features are available before trying to * use them (like trying to close the tray in drives that can't). @@ -182,12 +182,26 @@ * -- fix speed display for ACER 24X, 18X * 4.09 Jan 04, 1998 -- fix handling of the last block so we return * an end of file instead of an I/O error (Gadi) + * 4.10 Jan 24, 1998 -- fixed a bug so now changers can change to a new + * slot when there is no disc in the current slot. + * -- Fixed a memory leak where info->changer_info was + * malloc'ed but never free'd when closing the device. + * -- Cleaned up the global namespace a bit by making more + * functions static that should already have been. + * 4.11 Mar 12, 1998 -- Added support for the CDROM_SELECT_SPEED ioctl + * based on a patch for 2.0.33 by Jelle Foks + * , a patch for 2.0.33 + * by Toni Giorgino , the SCSI + * version, and my own efforts. -erik + * -- Fixed a stupid bug which egcs was kind enough to + * inform me of where "Illegal mode for this track" + * was never returned due to a comparison on data + * types of limited range. * *************************************************************************/ -#define IDECD_VERSION "4.09" +#define IDECD_VERSION "4.11" -#include #include #include #include @@ -265,8 +279,7 @@ printk (" Error code: 0x%02x\n", reqbuf->error_code); - if (reqbuf->sense_key >= 0 && - reqbuf->sense_key < ARY_LEN (sense_key_texts)) + if ( reqbuf->sense_key < ARY_LEN (sense_key_texts)) s = sense_key_texts[reqbuf->sense_key]; else s = "(bad sense key)"; @@ -279,7 +292,7 @@ s = buf; } else { int lo, hi; - int key = (reqbuf->asc << 8); + unsigned short key = (reqbuf->asc << 8); if ( ! (reqbuf->ascq >= 0x80 && reqbuf->ascq <= 0xdd) ) key |= reqbuf->ascq; @@ -490,7 +503,7 @@ } else if (sense_key == UNIT_ATTENTION) { /* Check for media change. */ cdrom_saw_media_change (drive); - printk ("%s: media changed\n", drive->name); + /*printk("%s: media changed\n",drive->name);*/ return 0; } else { /* Otherwise, print an error. */ @@ -1309,7 +1322,7 @@ /**************************************************************************** * cdrom driver request routine. */ - +static void ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block) { if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND) @@ -1512,7 +1525,6 @@ return cdrom_queue_packet_command (drive, &pc); } - static int cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity, struct atapi_request_sense *reqbuf) @@ -1715,7 +1727,6 @@ return cdrom_queue_packet_command (drive, &pc); } - static int cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen, struct atapi_request_sense *reqbuf) @@ -1736,6 +1747,43 @@ } +/* Note that this takes speed in kbytes/second, so don't try requesting + silly speeds like 2 here. Common speeds include: + 176 kbytes/second -- 1x + 353 kbytes/second -- 2x + 387 kbytes/second -- 2.2x + 528 kbytes/second -- 3x + 706 kbytes/second -- 4x + 1400 kbytes/second -- 8x + 2800 kbytes/second -- 16x + ATAPI 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 +cdrom_select_speed (ide_drive_t *drive, int speed, + struct atapi_request_sense *reqbuf) +{ + struct packet_command pc; + memset (&pc, 0, sizeof (pc)); + pc.sense_data = reqbuf; + + if (speed < 1) + speed = 0xffff; /* set to max */ + else + speed *= 177; /* Nx to kbytes/s */ + + pc.c[0] = SET_CD_SPEED; + /* Read Drive speed in kbytes/second MSB */ + pc.c[2] = (speed >> 8) & 0xff; + /* Read Drive speed in kbytes/second LSB */ + pc.c[3] = speed & 0xff; + /* Write Drive speed in kbytes/second MSB */ + //pc.c[4] = (speed >> 8) & 0xff; + /* Write Drive speed in kbytes/second LSB */ + //pc.c[5] = speed & 0xff; + + return cdrom_queue_packet_command (drive, &pc); +} + static int cdrom_play_lba_range_1 (ide_drive_t *drive, int lba_start, int lba_end, struct atapi_request_sense *reqbuf) @@ -2423,6 +2471,44 @@ return cdrom_lockdoor (drive, lock, NULL); } +static +int ide_cdrom_select_speed (struct cdrom_device_info *cdi, int speed) +{ + int stat, attempts = 3; + struct { + char pad[8]; + struct atapi_capabilities_page cap; + } buf; + ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct atapi_request_sense reqbuf; + stat=cdrom_select_speed (drive, speed, &reqbuf); + if (stat<0) + return stat; + + /* Now that that is done, update the speed fields */ + do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ + if (attempts-- <= 0) + return 0; + stat = cdrom_mode_sense (drive, PAGE_CAPABILITIES, 0, + (char *)&buf, sizeof (buf), NULL); + } while (stat); + + /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ + if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { + CDROM_STATE_FLAGS (drive)->current_speed = + (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; + } else { + CDROM_STATE_FLAGS (drive)->current_speed = + (ntohs(buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (ntohs(buf.cap.maxspeed) + (176/2)) / 176; + } + cdi->speed = CDROM_STATE_FLAGS (drive)->current_speed; + return 0; +} + static int ide_cdrom_select_disc (struct cdrom_device_info *cdi, int slot) @@ -2467,10 +2553,6 @@ if (drive->usage > 1) return -EBUSY; - stat = cdrom_check_status (drive, &my_reqbuf); - if (stat && my_reqbuf.sense_key == NOT_READY) - return -ENOENT; - if (slot == CDSL_NONE) { (void) cdrom_load_unload (drive, -1, NULL); cdrom_saw_media_change (drive); @@ -2666,14 +2748,14 @@ ide_cdrom_check_media_change_real, /* media_changed */ ide_cdrom_tray_move, /* tray_move */ ide_cdrom_lock_door, /* lock_door */ - NULL, /* select_speed */ + ide_cdrom_select_speed, /* select_speed */ ide_cdrom_select_disc, /* select_disc */ ide_cdrom_get_last_session, /* get_last_session */ ide_cdrom_get_mcn, /* get_mcn */ ide_cdrom_reset, /* reset */ ide_cdrom_audio_ioctl, /* audio_ioctl */ ide_cdrom_dev_ioctl, /* dev_ioctl */ - CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK + CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS, /* capability */ @@ -2689,7 +2771,7 @@ devinfo->dev = MKDEV (HWIF(drive)->major, minor); devinfo->ops = &ide_cdrom_dops; devinfo->mask = 0; - *(int *)&devinfo->speed = CDROM_CONFIG_FLAGS (drive)->max_speed; + *(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed; *(int *)&devinfo->capacity = nslots; devinfo->handle = (void *) drive; strcpy(devinfo->name, drive->name); @@ -2748,11 +2830,15 @@ /* The ACER/AOpen 24X cdrom has the speed fields byte-swapped */ if (drive->id && !drive->id->model[0] && !strncmp(drive->id->fw_rev, "241N", 4)) { - CDROM_STATE_FLAGS (drive)->current_speed = (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; + CDROM_STATE_FLAGS (drive)->current_speed = + (((unsigned int)buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (((unsigned int)buf.cap.maxspeed) + (176/2)) / 176; } else { - CDROM_STATE_FLAGS (drive)->current_speed = (ntohs(buf.cap.curspeed) + (176/2)) / 176; - CDROM_CONFIG_FLAGS (drive)->max_speed = (ntohs(buf.cap.maxspeed) + (176/2)) / 176; + CDROM_STATE_FLAGS (drive)->current_speed = + (ntohs(buf.cap.curspeed) + (176/2)) / 176; + CDROM_CONFIG_FLAGS (drive)->max_speed = + (ntohs(buf.cap.maxspeed) + (176/2)) / 176; } printk ("%s: ATAPI %dX CDROM", @@ -2765,8 +2851,7 @@ printk (" changer w/%d slots", nslots); else printk (" drive"); - printk (" %s/%dkB Cache\n", - (CDROM_CONFIG_FLAGS (drive)->is_changer)? "&" : "w", + printk (", %dkB Cache\n", ntohs(buf.cap.buffer_size) ); return nslots; @@ -2900,7 +2985,7 @@ } /* Forwarding functions to generic routines. */ - +static int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -2908,6 +2993,7 @@ return cdrom_fops.ioctl (inode, file, cmd, arg); } +static int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive) { int rc; @@ -2921,6 +3007,7 @@ return rc; } +static void ide_cdrom_release (struct inode *inode, struct file *file, ide_drive_t *drive) { @@ -2928,6 +3015,7 @@ MOD_DEC_USE_COUNT; } +static int ide_cdrom_check_media_change (ide_drive_t *drive) { return cdrom_fops.check_media_change @@ -2936,6 +3024,7 @@ } +static int ide_cdrom_cleanup(ide_drive_t *drive) { struct cdrom_info *info = drive->driver_data; @@ -2947,6 +3036,8 @@ kfree (info->sector_buffer); if (info->toc != NULL) kfree (info->toc); + if (info->changer_info != NULL) + kfree (info->changer_info); if (devinfo->handle == drive && unregister_cdrom (devinfo)) printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name); kfree (info); 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 Wed Dec 17 20:11:51 1997 +++ new/linux/drivers/block/ide-cd.h Wed Mar 18 06:39:11 1998 @@ -71,7 +71,7 @@ #define MODE_SENSE_10 0x5a #define MODE_SELECT_10 0x55 #define READ_CD 0xbe - +#define SET_CD_SPEED 0xbb #define LOAD_UNLOAD 0xa6 #define MECHANISM_STATUS 0xbd @@ -431,7 +431,7 @@ with additions from Tables 141 and 142 of the ATAPI 2.6 draft standard. */ struct { - short asc_ascq; + unsigned short asc_ascq; char *text; } sense_data_texts[] = { { 0x0000, "No additional sense information" }, 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 Sat Jan 10 19:42:55 1998 +++ new/linux/drivers/block/ide-disk.c Tue Mar 10 19:48:27 1998 @@ -16,9 +16,11 @@ * Version 1.02 remove ", LBA" from drive identification msgs * Version 1.03 fix display of id->buf_size for big-endian * Version 1.04 add /proc configurable settings and S.M.A.R.T support + * Version 1.05 add capacity support for ATA3 >= 8GB + * Version 1.06 get boot-up messages to show full cyl count */ -#define IDEDISK_VERSION "1.04" +#define IDEDISK_VERSION "1.06" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -83,6 +85,11 @@ unsigned long chs_sects = id->cyls * id->heads * id->sectors; unsigned long _10_percent = chs_sects / 10; + /* very large drives (8GB+) may lie about the number of cylinders */ + if (id->cyls == 16383 && id->heads == 16 && id->sectors == 63 && lba_sects > chs_sects) { + 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 */ @@ -105,12 +112,15 @@ int i; unsigned int msect, nsect; struct request *rq; + unsigned long flags; if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) { ide_error(drive, "read_intr", stat); return; } msect = drive->mult_count; + + spin_lock_irqsave(&io_request_lock,flags); read_next: rq = HWGROUP(drive)->rq; if (msect) { @@ -119,6 +129,12 @@ msect -= nsect; } else nsect = 1; + /* + * PIO input can take longish times, so we drop the spinlock. + * On SMP, bad things might happen if syscall level code adds + * a new request while we do this PIO, so we just freeze all + * request queue handling while doing the PIO. FIXME + */ idedisk_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); #ifdef DEBUG printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n", @@ -136,6 +152,7 @@ goto read_next; ide_set_handler (drive, &read_intr, WAIT_CMD); } + spin_unlock_irqrestore(&io_request_lock,flags); } /* @@ -147,7 +164,10 @@ int i; ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = hwgroup->rq; + unsigned long flags; + int error = 0; + spin_lock_irqsave(&io_request_lock,flags); if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { #ifdef DEBUG printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n", @@ -166,10 +186,16 @@ idedisk_output_data (drive, rq->buffer, SECTOR_WORDS); ide_set_handler (drive, &write_intr, WAIT_CMD); } - return; + goto out; } - } - ide_error(drive, "write_intr", stat); + } else + error = 1; + +out: + spin_unlock_irqrestore(&io_request_lock,flags); + + if (error) + ide_error(drive, "write_intr", stat); } /* @@ -217,13 +243,16 @@ int i; ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = &hwgroup->wrq; + unsigned long flags; + int error = 0; + spin_lock_irqsave(&io_request_lock,flags); if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) { if (stat & DRQ_STAT) { if (rq->nr_sectors) { ide_multwrite(drive, drive->mult_count); ide_set_handler (drive, &multwrite_intr, WAIT_CMD); - return; + goto out; } } else { if (!rq->nr_sectors) { /* all done? */ @@ -232,11 +261,17 @@ i -= rq->current_nr_sectors; ide_end_request(1, hwgroup); } - return; + goto out; } } - } - ide_error(drive, "multwrite_intr", stat); + } else + error = 1; + +out: + spin_unlock_irqrestore(&io_request_lock,flags); + + if (error) + ide_error(drive, "multwrite_intr", stat); } /* @@ -354,7 +389,7 @@ return; } if (!drive->unmask) - cli(); + __cli(); if (drive->mult_count) { HWGROUP(drive)->wrq = *rq; /* scratchpad */ ide_set_handler (drive, &multwrite_intr, WAIT_CMD); @@ -411,6 +446,7 @@ /* Determine capacity, and use LBA if the drive properly supports it */ if (id != NULL && (id->capability & 2) && lba_capacity_is_ok(id)) { if (id->lba_capacity >= capacity) { + drive->cyl = id->lba_capacity / (drive->head * drive->sect); capacity = id->lba_capacity; drive->select.b.lba = 1; } @@ -670,6 +706,10 @@ drive->head = id->heads; drive->sect = id->sectors; } + + /* calculate drive capacity, and select LBA if possible */ + (void) idedisk_capacity (drive); + /* Correct the number of cyls if the bios value is too small */ if (drive->sect == drive->bios_sect && drive->head == drive->bios_head) { if (drive->cyl > drive->bios_cyl) @@ -677,8 +717,6 @@ } /* fix byte-ordering of buffer size field */ id->buf_size = le16_to_cpu(id->buf_size); - - (void) idedisk_capacity (drive); /* initialize LBA selection */ printk (KERN_INFO "%s: %.40s, %ldMB w/%dkB Cache, CHS=%d/%d/%d", drive->name, id->model, idedisk_capacity(drive)/2048L, id->buf_size/2, 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 Thu Jan 1 01:42:56 1998 +++ new/linux/drivers/block/ide-dma.c Fri Jan 16 05:51:04 1998 @@ -306,7 +306,7 @@ * safely use __get_free_page() here instead * of __get_dma_pages() -- no ISA limitations. */ - dmatable = __get_free_pages(GFP_KERNEL,1,0); + dmatable = __get_free_pages(GFP_KERNEL,1); leftover = dmatable ? PAGE_SIZE : 0; } if (!dmatable) { diff -ur --new-file old/linux/drivers/block/ide-pci.c new/linux/drivers/block/ide-pci.c --- old/linux/drivers/block/ide-pci.c Thu Jan 1 01:42:56 1998 +++ new/linux/drivers/block/ide-pci.c Thu Mar 12 01:18:29 1998 @@ -24,7 +24,8 @@ #include "ide.h" -#define DEVID_PIIX ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1}) +#define DEVID_PIIXa ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0}) +#define DEVID_PIIXb ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1}) #define DEVID_PIIX3 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1}) #define DEVID_PIIX4 ((ide_pci_devid_t){PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB}) #define DEVID_VP_IDE ((ide_pci_devid_t){PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1}) @@ -87,7 +88,8 @@ } ide_pci_device_t; static ide_pci_device_t ide_pci_chipsets[] __initdata = { - {DEVID_PIIX, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, + {DEVID_PIIXa, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, + {DEVID_PIIXb, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, {DEVID_PIIX3, "PIIX3", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, {DEVID_PIIX4, "PIIX4", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}} }, {DEVID_VP_IDE, "VP_IDE", NULL, {{0x40,0x02,0x02}, {0x40,0x01,0x01}} }, @@ -360,6 +362,13 @@ || IDE_PCI_DEVID_EQ(devid, IDE_PCI_DEVID_NULL) || pcibios_read_config_dword(bus, fn, 0x08, &ccode)) return; + /* + * workaround Intel Advanced/ZP with bios <= 1.04; + * these appear in some Dell Dimension XPS's + */ + if (!hedt && IDE_PCI_DEVID_EQ(devid, DEVID_PIIXa)) + hedt = 0x80; + for (d = ide_pci_chipsets; d->devid.vid && !IDE_PCI_DEVID_EQ(d->devid, devid); ++d); if (d->init_hwif == IDE_IGNORE) printk("%s: ignored by ide_scan_pci_device() (uses own driver)\n", d->name); diff -ur --new-file old/linux/drivers/block/ide-proc.c new/linux/drivers/block/ide-proc.c --- old/linux/drivers/block/ide-proc.c Sat Jan 10 19:42:55 1998 +++ new/linux/drivers/block/ide-proc.c Sun Mar 1 19:20:27 1998 @@ -87,16 +87,6 @@ return digit; } -static int ide_getdigit(char c) -{ - int digit; - if (isdigit(c)) - digit = c - '0'; - else - digit = -1; - return digit; -} - static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg) { char errbuf[16]; @@ -254,24 +244,6 @@ return xx_xx_parse_error(start, startn, msg); } -static int proc_ide_read_drivers - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - char *out = page; - int len; - ide_module_t *p = ide_modules; - ide_driver_t *driver; - - while (p) { - driver = (ide_driver_t *) p->info; - if (p->type == IDE_DRIVER_MODULE && driver) - out += sprintf(out, "%s version %s\n", driver->name, driver->version); - p = p->next; - } - len = out - page; - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - static int proc_ide_read_config (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -302,15 +274,40 @@ { ide_hwif_t *hwif = (ide_hwif_t *) data; int len; - const char *vids, *dids; - vids = pci_strvendor(hwif->pci_devid.vid); - dids = pci_strdev(hwif->pci_devid.vid, hwif->pci_devid.did); - len = sprintf(page,"%s: %s\n", vids ? vids : "(none)", dids ? dids : "(none)"); + len = sprintf(page,"%04x: %04x\n", hwif->pci_devid.vid, hwif->pci_devid.did); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } #endif /* CONFIG_PCI */ +static int ide_getdigit(char c) +{ + int digit; + if (isdigit(c)) + digit = c - '0'; + else + digit = -1; + return digit; +} + +static int proc_ide_read_drivers + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *out = page; + int len; + ide_module_t *p = ide_modules; + ide_driver_t *driver; + + while (p) { + driver = (ide_driver_t *) p->info; + if (p->type == IDE_DRIVER_MODULE && driver) + out += sprintf(out, "%s version %s\n", driver->name, driver->version); + p = p->next; + } + len = out - page; + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + static int proc_ide_read_type (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -616,8 +613,12 @@ if (!drive->proc || !p) return; while (p->name != NULL) { - ent = create_proc_entry(p->name, 0, drive->proc); + mode_t mode = S_IFREG|S_IRUSR; + if (!strcmp(p->name,"settings")) + mode |= S_IWUSR; + ent = create_proc_entry(p->name, mode, drive->proc); if (!ent) return; + ent->nlink = 1; ent->data = drive; ent->read_proc = p->read_proc; ent->write_proc = p->write_proc; @@ -677,8 +678,9 @@ if (!hwif_ent) return; #ifdef CONFIG_PCI if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) { - ent = create_proc_entry("config", 0, hwif_ent); + ent = create_proc_entry("config", S_IFREG|S_IRUSR|S_IWUSR, hwif_ent); if (!ent) return; + ent->nlink = 1; ent->data = hwif; ent->read_proc = proc_ide_read_config; ent->write_proc = proc_ide_write_config;; diff -ur --new-file old/linux/drivers/block/ide.c new/linux/drivers/block/ide.c --- old/linux/drivers/block/ide.c Sat Jan 10 19:42:55 1998 +++ new/linux/drivers/block/ide.c Tue Mar 10 23:43:13 1998 @@ -134,9 +134,9 @@ #include "ide.h" #include "ide_modes.h" -#ifdef CONFIG_KERNELD -#include -#endif /* CONFIG_KERNELD */ +#ifdef CONFIG_KMOD +#include +#endif /* CONFIG_KMOD */ static const byte ide_hwif_to_major[] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR}; @@ -170,13 +170,13 @@ unsigned long t, flags; int i; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); i |= inb(0x40) << 8; - restore_flags(flags); + __restore_flags(flags); return (t - i); } #endif /* DISK_RECOVERY_TIME */ @@ -314,11 +314,11 @@ #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); do_vlb_sync(IDE_NSECTOR_REG); insl(IDE_DATA_REG, buffer, wcount); - restore_flags(flags); + __restore_flags(flags); } else #endif /* SUPPORT_VLB_SYNC */ insl(IDE_DATA_REG, buffer, wcount); @@ -347,11 +347,11 @@ #if SUPPORT_VLB_SYNC if (io_32bit & 2) { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); do_vlb_sync(IDE_NSECTOR_REG); outsl(IDE_DATA_REG, buffer, wcount); - restore_flags(flags); + __restore_flags(flags); } else #endif /* SUPPORT_VLB_SYNC */ outsl(IDE_DATA_REG, buffer, wcount); @@ -573,8 +573,8 @@ ide_hwif_t *hwif = HWIF(drive); ide_hwgroup_t *hwgroup = HWGROUP(drive); - save_flags(flags); - cli(); /* Why ? */ + __save_flags(flags); + __cli(); /* Why ? */ /* For an ATAPI device, first try an ATAPI SRST. */ if (drive->media != ide_disk && !do_not_try_atapi) { @@ -584,7 +584,7 @@ OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20); - restore_flags (flags); + __restore_flags (flags); return; } @@ -612,7 +612,7 @@ ide_set_handler (drive, &reset_pollfunc, HZ/20); #endif /* OK_TO_RESET_CONTROLLER */ - restore_flags (flags); + __restore_flags (flags); } /* @@ -640,15 +640,15 @@ args[2] = IN_BYTE(IDE_NSECTOR_REG); } } - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); drive->queue = rq->next; blk_dev[MAJOR(rq->rq_dev)].current_request = NULL; HWGROUP(drive)->rq = NULL; rq->rq_status = RQ_INACTIVE; if (rq->sem != NULL) up(rq->sem); - restore_flags(flags); + __restore_flags(flags); } /* @@ -659,8 +659,8 @@ unsigned long flags; byte err = 0; - save_flags (flags); - ide_sti(); + __save_flags (flags); + /* ide_sti(); HACK */ printk("%s: %s: status=0x%02x", drive->name, msg, stat); #if FANCY_STATUS_DUMPS printk(" { "); @@ -713,7 +713,7 @@ #endif /* FANCY_STATUS_DUMPS */ printk("\n"); } - restore_flags (flags); + __restore_flags (flags); return err; } @@ -814,7 +814,7 @@ byte stat = GET_STAT(); int retries = 10; - ide_sti(); + /* ide_sti(); HACK */ if ((stat & DRQ_STAT) && args && args[3]) { byte io_32bit = drive->io_32bit; drive->io_32bit = 0; @@ -872,17 +872,17 @@ udelay(1); /* spec allows drive 400ns to assert "BUSY" */ if ((stat = GET_STAT()) & BUSY_STAT) { - save_flags(flags); - ide_sti(); + __save_flags(flags); + /* ide_sti(); HACK */ timeout += jiffies; while ((stat = GET_STAT()) & BUSY_STAT) { if (0 < (signed long)(jiffies - timeout)) { - restore_flags(flags); + __restore_flags(flags); ide_error(drive, "status timeout", stat); return 1; } } - restore_flags(flags); + __restore_flags(flags); } udelay(1); /* allow status to settle, then read it again */ if (OK_STAT((stat = GET_STAT()), good, bad)) @@ -932,7 +932,7 @@ struct request *rq = drive->queue; unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS; - ide_sti(); + /* ide_sti(); HACK */ #ifdef DEBUG printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq); #endif @@ -1093,7 +1093,7 @@ */ void ide_do_request (ide_hwgroup_t *hwgroup) { - cli(); /* paranoia */ + __cli(); /* paranoia */ if (hwgroup->handler != NULL) { printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name); return; @@ -1108,7 +1108,7 @@ blk_dev[hwif->major].current_request = hwgroup->rq = drive->queue; drive->service_start = jiffies; do_request(hwgroup, hwif, drive); - cli(); + __cli(); } else { ide_leave_hwgroup(hwgroup); /* no work left for this hwgroup */ return; @@ -1157,27 +1157,27 @@ } } -void do_ide0_request (void) /* invoked with cli() */ +void do_ide0_request (void) /* invoked with __cli() */ { do_hwgroup_request (ide_hwifs[0].hwgroup); } #if MAX_HWIFS > 1 -void do_ide1_request (void) /* invoked with cli() */ +void do_ide1_request (void) /* invoked with __cli() */ { do_hwgroup_request (ide_hwifs[1].hwgroup); } #endif /* MAX_HWIFS > 1 */ #if MAX_HWIFS > 2 -void do_ide2_request (void) /* invoked with cli() */ +void do_ide2_request (void) /* invoked with __cli() */ { do_hwgroup_request (ide_hwifs[2].hwgroup); } #endif /* MAX_HWIFS > 2 */ #if MAX_HWIFS > 3 -void do_ide3_request (void) /* invoked with cli() */ +void do_ide3_request (void) /* invoked with __cli() */ { do_hwgroup_request (ide_hwifs[3].hwgroup); } @@ -1190,8 +1190,8 @@ ide_handler_t *handler; unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if ((handler = hwgroup->handler) != NULL) { hwgroup->handler = NULL; @@ -1202,7 +1202,7 @@ (void) hwgroup->hwif->dmaproc (ide_dma_end, drive); ide_error(drive, "irq timeout", GET_STAT()); } - cli(); + __cli(); if (hwgroup->handler == NULL) { set_recovery_timer(HWIF(drive)); drive->service_time = jiffies - drive->service_start; @@ -1210,7 +1210,7 @@ } } else do_hwgroup_request (hwgroup); - restore_flags(flags); + __restore_flags(flags); } /* @@ -1223,7 +1223,7 @@ * drive enters "idle", "standby", or "sleep" mode, so if the status looks * "good", we just ignore the interrupt completely. * - * This routine assumes cli() is in effect when called. + * This routine assumes __cli() is in effect when called. * * If an unexpected interrupt happens on irq15 while we are handling irq14 * and if the two interfaces are "serialized" (CMD640), then it looks like @@ -1261,10 +1261,11 @@ } /* - * entry point for all interrupts, caller does cli() for us + * entry point for all interrupts, caller does __cli() for us */ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; ide_hwgroup_t *hwgroup = dev_id; ide_hwif_t *hwif = hwgroup->hwif; ide_handler_t *handler; @@ -1290,19 +1291,21 @@ #endif /* temporary */ hwgroup->handler = NULL; del_timer(&(hwgroup->timer)); - if (drive->unmask) - ide_sti(); + /* if (drive->unmask) + ide_sti(); HACK */ handler(drive); - cli(); /* this is necessary, as next rq may be different irq */ + /* this is necessary, as next rq may be different irq */ + spin_lock_irqsave(&io_request_lock,flags); if (hwgroup->handler == NULL) { set_recovery_timer(HWIF(drive)); drive->service_time = jiffies - drive->service_start; ide_do_request(hwgroup); } + spin_unlock_irqrestore(&io_request_lock,flags); } else { unexpected_intr(irq, hwgroup); } - cli(); + __cli(); hwif = hwgroup->hwif; do { if (hwif->irq != irq) enable_irq(hwif->irq); @@ -1390,8 +1393,8 @@ if (action == ide_wait) rq->sem = &sem; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); cur_rq = drive->queue; if (cur_rq == NULL || action == ide_preempt) { @@ -1409,11 +1412,11 @@ } if (!hwgroup->active) { do_hwgroup_request(hwgroup); - cli(); + __cli(); } if (action == ide_wait && rq->rq_status != RQ_INACTIVE) down(&sem); /* wait for it to be serviced */ - restore_flags(flags); + __restore_flags(flags); return rq->errors ? -EIO : 0; /* return -EIO if errors */ } @@ -1435,15 +1438,15 @@ return -ENODEV; major = MAJOR(i_rdev); minor = drive->select.b.unit << PARTN_BITS; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if (drive->busy || (drive->usage > 1)) { - restore_flags(flags); + __restore_flags(flags); return -EBUSY; }; drive->busy = 1; MOD_INC_USE_COUNT; - restore_flags(flags); + __restore_flags(flags); for (p = 0; p < (1<part[p].nr_sects > 0) { @@ -1502,10 +1505,10 @@ module = module->next; } revalidate_drives(); -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (!found && type == IDE_PROBE_MODULE) (void) request_module("ide-probe"); -#endif /* CONFIG_KERNELD */ +#endif /* CONFIG_KMOD */ } static int ide_open(struct inode * inode, struct file * filp) @@ -1518,7 +1521,7 @@ MOD_INC_USE_COUNT; if (drive->driver == NULL) ide_init_module(IDE_DRIVER_MODULE); -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (drive->driver == NULL) { if (drive->media == ide_disk) (void) request_module("ide-disk"); @@ -1529,7 +1532,7 @@ if (drive->media == ide_floppy) (void) request_module("ide-floppy"); } -#endif /* CONFIG_KERNELD */ +#endif /* CONFIG_KMOD */ while (drive->busy) sleep_on(&drive->wqueue); drive->usage++; @@ -1589,8 +1592,8 @@ if (index >= MAX_HWIFS) return; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); hwif = &ide_hwifs[index]; if (!hwif->present) goto abort; @@ -1680,7 +1683,7 @@ } init_hwif_data (index); /* restore hwif data to pristine status */ abort: - restore_flags(flags); + __restore_flags(flags); } int ide_register (int arg1, int arg2, int irq) @@ -1825,8 +1828,8 @@ return -EPERM; if (val < setting->min || val > setting->max) return -EINVAL; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if (setting->set) rc = setting->set(drive, val); else switch (setting->data_type) { @@ -1845,7 +1848,7 @@ *p = val; break; } - restore_flags(flags); + __restore_flags(flags); return rc; } @@ -2697,16 +2700,16 @@ { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) { - restore_flags(flags); + __restore_flags(flags); return 1; } drive->driver = driver; setup_driver_defaults(drive); - restore_flags(flags); + __restore_flags(flags); if (drive->autotune != 2) { if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) (void) (HWIF(drive)->dmaproc(ide_dma_check, drive)); @@ -2723,17 +2726,17 @@ { unsigned long flags; - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) { - restore_flags(flags); + __restore_flags(flags); return 1; } ide_remove_proc_entries(drive, DRIVER(drive)->proc); ide_remove_proc_entries(drive, generic_subdriver_entries); auto_remove_settings(drive); drive->driver = NULL; - restore_flags(flags); + __restore_flags(flags); return 0; } @@ -2790,6 +2793,7 @@ EXPORT_SYMBOL(ide_fops); EXPORT_SYMBOL(ide_get_queue); EXPORT_SYMBOL(do_ide0_request); +EXPORT_SYMBOL(ide_add_generic_settings); #if MAX_HWIFS > 1 EXPORT_SYMBOL(do_ide1_request); #endif /* MAX_HWIFS > 1 */ @@ -2822,6 +2826,7 @@ EXPORT_SYMBOL(ide_end_request); EXPORT_SYMBOL(ide_revalidate_disk); EXPORT_SYMBOL(ide_cmd); +EXPORT_SYMBOL(ide_wait_cmd); EXPORT_SYMBOL(ide_stall_queue); EXPORT_SYMBOL(ide_add_proc_entries); EXPORT_SYMBOL(ide_remove_proc_entries); 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 Sun Dec 28 21:05:44 1997 +++ new/linux/drivers/block/ll_rw_blk.c Thu Mar 12 00:07:43 1998 @@ -22,6 +22,8 @@ #include #include +#include + /* * The request-struct contains all necessary data * to load a nr of sectors into memory @@ -35,6 +37,11 @@ DECLARE_TASK_QUEUE(tq_disk); /* + * Protect the request list against multiple users.. + */ +spinlock_t io_request_lock = SPIN_LOCK_UNLOCKED; + +/* * used to wait on when there are no free requests */ struct wait_queue * wait_for_request = NULL; @@ -335,6 +342,7 @@ unsigned int sector, count; struct request * req; int rw_ahead, max_req, max_sectors; + unsigned long flags; count = bh->b_size >> 9; sector = bh->b_rsector; @@ -402,13 +410,18 @@ * Try to coalesce the new request with old requests */ max_sectors = get_max_sectors(bh->b_rdev); - cli(); + + /* + * Now we acquire the request spinlock, we have to be mega careful + * not to schedule or do something nonatomic + */ + spin_lock_irqsave(&io_request_lock,flags); req = *get_queue(bh->b_rdev); if (!req) { /* MD and loop can't handle plugging without deadlocking */ if (major != MD_MAJOR && major != LOOP_MAJOR && major != DDV_MAJOR) - plug_device(blk_dev + major); + plug_device(blk_dev + major); /* is atomic */ } else switch (major) { case IDE0_MAJOR: /* same as HD_MAJOR */ case IDE1_MAJOR: @@ -462,14 +475,16 @@ continue; mark_buffer_clean(bh); - sti(); + spin_unlock_irqrestore(&io_request_lock,flags); return; + } while ((req = req->next) != NULL); } /* find an unused request. */ req = get_request(max_req, bh->b_rdev); - sti(); + + spin_unlock_irqrestore(&io_request_lock,flags); /* if no request available: if rw_ahead, forget it; otherwise try again blocking.. */ if (!req) { @@ -641,9 +656,10 @@ if (j == 0) { req[j] = get_request_wait(max_req, rdev); } else { - cli(); + unsigned long flags; + spin_lock_irqsave(&io_request_lock,flags); req[j] = get_request(max_req, rdev); - sti(); + spin_unlock_irqrestore(&io_request_lock,flags); if (req[j] == NULL) break; } @@ -774,4 +790,6 @@ ddv_init(); #endif return 0; -} +}; + +EXPORT_SYMBOL(io_request_lock); diff -ur --new-file old/linux/drivers/block/md.c new/linux/drivers/block/md.c --- old/linux/drivers/block/md.c Mon Dec 1 23:47:07 1997 +++ new/linux/drivers/block/md.c Tue Mar 10 23:43:13 1998 @@ -8,9 +8,13 @@ A lot of inspiration came from hd.c ... kerneld support by Boris Tobotras + boot support for linear and striped mode by Harald Hoyer RAID-1/RAID-5 extensions by: Ingo Molnar, Miguel de Icaza, Gadi Oxman + + Changes for kmod by: + Cyrus Durgin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,8 +46,8 @@ #include #include #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif #include #include @@ -59,6 +63,10 @@ #include #include +#ifdef CONFIG_MD_BOOT +extern kdev_t name_to_kdev_t(char *line) __init; +#endif + static struct hd_struct md_hd_struct[MAX_MD_DEV]; static int md_blocksizes[MAX_MD_DEV]; int md_maxreadahead[MAX_MD_DEV]; @@ -426,7 +434,7 @@ } if (!pers[pnum]) { -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD char module_name[80]; sprintf (module_name, "md-personality-%d", pnum); request_module (module_name); @@ -846,6 +854,7 @@ static struct proc_dir_entry proc_md = { PROC_MD, 6, "mdstat", S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, }; static void md_geninit (struct gendisk *gdisk) @@ -987,10 +996,13 @@ cli(); if (!test_bit(THREAD_WAKEUP, &thread->flags)) { do { - spin_lock_irq(¤t->sigmask_lock); + spin_lock(¤t->sigmask_lock); flush_signals(current); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock(¤t->sigmask_lock); interruptible_sleep_on(&thread->wqueue); + cli(); + if (test_bit(THREAD_WAKEUP, &thread->flags)) + break; } while (signal_pending(current)); } } @@ -1054,7 +1066,7 @@ */ curr_bsize = blksize_size[major][minor]; if (curr_bsize != blocksize) { -diff_blocksize: + diff_blocksize: if (curr_bsize > blocksize) /* * this is safe, rounds downwards. @@ -1162,6 +1174,102 @@ } +#ifdef CONFIG_MD_BOOT +struct { + int set; + int ints[100]; + char str[100]; +} md_setup_args __initdata = { + 0,{0},{0} +}; + +/* called from init/main.c */ +__initfunc(void md_setup(char *str,int *ints)) +{ + int i; + for(i=0;i<=ints[0];i++) { + md_setup_args.ints[i] = ints[i]; + strcpy(md_setup_args.str, str); +/* printk ("md: ints[%d]=%d.\n", i, ints[i]);*/ + } + md_setup_args.set=1; + return; +} + +__initfunc(void do_md_setup(char *str,int *ints)) +{ + int minor, pers, factor, fault; + kdev_t dev; + int i=1; + + if(ints[0] < 4) { + printk ("md: Too few Arguments (%d).\n", ints[0]); + return; + } + + minor=ints[i++]; + + if (minor >= MAX_MD_DEV) { + printk ("md: Minor device number too high.\n"); + return; + } + + pers = 0; + + switch(ints[i++]) { /* Raidlevel */ + case -1: +#ifdef CONFIG_MD_LINEAR + pers = LINEAR; + printk ("md: Setting up md%d as linear device.\n",minor); +#else + printk ("md: Linear mode not configured." + "Recompile the kernel with linear mode enabled!\n"); +#endif + break; + case 0: + pers = STRIPED; +#ifdef CONFIG_MD_STRIPED + printk ("md: Setting up md%d as a striped device.\n",minor); +#else + printk ("md: Striped mode not configured." + "Recompile the kernel with striped mode enabled!\n"); +#endif + break; +/* not supported yet + case 1: + pers = RAID1; + printk ("md: Setting up md%d as a raid1 device.\n",minor); + break; + case 5: + pers = RAID5; + printk ("md: Setting up md%d as a raid5 device.\n",minor); + break; +*/ + default: + printk ("md: Unknown or not supported raid level %d.\n", ints[--i]); + return; + } + + if(pers) { + + factor=ints[i++]; /* Chunksize */ + fault =ints[i++]; /* Faultlevel */ + + pers=pers | factor | (fault << FAULT_SHIFT); + + while( str && (dev = name_to_kdev_t(str))) { + do_md_add (minor, dev); + if((str = strchr (str, ',')) != NULL) + str++; + } + + do_md_run (minor, pers); + printk ("md: Loading md%d.\n",minor); + } + +} +#endif + void linear_init (void); void raid0_init (void); void raid1_init (void); @@ -1215,6 +1323,13 @@ #ifdef CONFIG_MD_RAID5 raid5_init (); #endif - return (0); } + +#ifdef CONFIG_MD_BOOT +__initfunc(void md_setup_drive(void)) +{ + if(md_setup_args.set) + do_md_setup(md_setup_args.str, md_setup_args.ints); +} +#endif diff -ur --new-file old/linux/drivers/block/paride/Config.in new/linux/drivers/block/paride/Config.in --- old/linux/drivers/block/paride/Config.in Sun Dec 28 21:05:45 1997 +++ new/linux/drivers/block/paride/Config.in Sun Jan 25 18:59:59 1998 @@ -5,6 +5,7 @@ dep_tristate ' Parallel port IDE disks' CONFIG_PARIDE_PD $CONFIG_PARIDE dep_tristate ' Parallel port ATAPI CD-ROMs' CONFIG_PARIDE_PCD $CONFIG_PARIDE dep_tristate ' Parallel port ATAPI disks' CONFIG_PARIDE_PF $CONFIG_PARIDE +dep_tristate ' Parallel port ATAPI tapes' CONFIG_PARIDE_PT $CONFIG_PARIDE comment 'Parallel IDE protocol modules' dep_tristate ' ATEN EH-100 protocol' CONFIG_PARIDE_ATEN $CONFIG_PARIDE dep_tristate ' MicroSolutions backpack protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE diff -ur --new-file old/linux/drivers/block/paride/Makefile new/linux/drivers/block/paride/Makefile --- old/linux/drivers/block/paride/Makefile Sun Dec 28 21:05:45 1997 +++ new/linux/drivers/block/paride/Makefile Sun Jan 25 18:59:59 1998 @@ -50,6 +50,14 @@ endif endif +ifeq ($(CONFIG_PARIDE_PT),y) + LX_OBJS += pt.o +else + ifeq ($(CONFIG_PARIDE_PT),m) + MX_OBJS += pt.o + endif +endif + ifeq ($(CONFIG_PARIDE_ATEN),y) LX_OBJS += aten.o else diff -ur --new-file old/linux/drivers/block/paride/paride.c new/linux/drivers/block/paride/paride.c --- old/linux/drivers/block/paride/paride.c Sun Dec 28 21:05:45 1997 +++ new/linux/drivers/block/paride/paride.c Sun Jan 25 18:59:59 1998 @@ -473,6 +473,11 @@ pf_init(); }; #endif +#ifdef CONFIG_PARIDE_PT + { extern int pt_init(void); + pt_init(); + }; +#endif } #endif diff -ur --new-file old/linux/drivers/block/paride/pcd.c new/linux/drivers/block/paride/pcd.c --- old/linux/drivers/block/paride/pcd.c Sun Dec 28 21:05:45 1997 +++ new/linux/drivers/block/paride/pcd.c Sun Jan 25 18:59:59 1998 @@ -83,7 +83,13 @@ */ -#define PCD_VERSION "1.0" +/* Changes: + + 1.01 GRG 1997.01.24 Added test unit ready support + +*/ + +#define PCD_VERSION "1.01" #define PCD_MAJOR 46 #define PCD_NAME "pcd" #define PCD_UNITS 4 @@ -173,6 +179,7 @@ #define PCD_RETRIES 5 #define PCD_TMO 800 /* timeout in jiffies */ #define PCD_DELAY 50 /* spin delay in uS */ +#define PCD_READY_TMO 20 #define PCD_SPIN (10000/PCD_DELAY)*PCD_TMO @@ -207,6 +214,7 @@ struct pi_adapter pia; /* interface to paride layer */ struct pi_adapter *pi; int drive; /* master/slave */ + int last_sense; /* result of last request sense */ int access; /* count of active opens */ int present; /* does this unit exist ? */ char name[PCD_NAMELEN]; /* pcd0, pcd1, etc */ @@ -264,6 +272,7 @@ PCD.pi = & PCD.pia; PCD.access = 0; PCD.present = 0; + PCD.last_sense = 0; j = 0; while ((j < PCD_NAMELEN-2) && (PCD.name[j]=name[j])) j++; PCD.name[j++] = '0' + unit; @@ -509,9 +518,13 @@ udelay(1000); if (!r) pcd_completion(unit,buf,"Request sense"); - if ((!r)&&(!quiet)) - printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n", - PCD.name,buf[2]&0xf,buf[12],buf[13]); + PCD.last_sense = -1; + if (!r) { + if (!quiet) printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n", + PCD.name,buf[2]&0xf,buf[12],buf[13]); + PCD.last_sense = (buf[2]&0xf) | ((buf[12]&0xff)<<8) + | ((buf[13]&0xff)<<16) ; + } } static int pcd_atapi( int unit, char * cmd, int dlen, char * buf, char * fun ) @@ -607,13 +620,30 @@ return flg-1; } +static int pcd_ready_wait( int unit, int tmo ) + +{ char tr_cmd[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + int k, p; + + k = 0; + while (k < tmo) { + PCD.last_sense = 0; + pcd_atapi(unit,tr_cmd,0,NULL,DBMSG("test unit ready")); + p = PCD.last_sense; + if (!p) return 0; + if (!((p == 0x010402)||((p & 0xff) == 6))) return p; + k++; + pcd_sleep(100); + } + return 0x000020; /* timeout */ +} + static int pcd_check_media( int unit ) { char rc_cmd[12] = { 0x25,0,0,0,0,0,0,0,0,0,0,0}; - pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("cm1")); - pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("cm2")); - return (pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("cm3"))); + pcd_ready_wait(unit,PCD_READY_TMO); + return (pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("check media"))); } static int pcd_identify( int unit, char * id ) diff -ur --new-file old/linux/drivers/block/paride/pd.c new/linux/drivers/block/paride/pd.c --- old/linux/drivers/block/paride/pd.c Sun Dec 28 21:05:45 1997 +++ new/linux/drivers/block/paride/pd.c Sun Jan 25 18:59:59 1998 @@ -96,7 +96,14 @@ */ -#define PD_VERSION "1.0" +/* Changes: + + 1.01 GRG 1997.01.24 Restored pd_reset() + Added eject ioctl + +*/ + +#define PD_VERSION "1.01" #define PD_MAJOR 45 #define PD_NAME "pd" #define PD_UNITS 4 @@ -141,6 +148,7 @@ #include #include #include +#include /* for the eject ioctl */ #include @@ -234,6 +242,7 @@ #define IDE_DOORLOCK 0xde #define IDE_DOORUNLOCK 0xdf #define IDE_IDENTIFY 0xec +#define IDE_EJECT 0xed int pd_init(void); void pd_setup(char * str, int * ints); @@ -257,6 +266,7 @@ static void pd_media_check(int unit); static void pd_doorlock(int unit, int func); static int pd_check_media(kdev_t dev); +static void pd_eject( int unit); static struct hd_struct pd_hd[PD_DEVS]; static int pd_sizes[PD_DEVS]; @@ -435,6 +445,9 @@ if (!PD.present) return -ENODEV; switch (cmd) { + case CDROMEJECT: + if (PD.access == 1) pd_eject(unit); + return 0; case HDIO_GETGEO: if (!geo) return -EINVAL; err = verify_area(VERIFY_WRITE,geo,sizeof(*geo)); @@ -642,7 +655,6 @@ printk("\n"); } -/* static void pd_reset( int unit ) { pi_connect(PI); @@ -650,8 +662,8 @@ udelay(50); WR(1,6,0); pi_disconnect(PI); + udelay(250); } -*/ #define DBMSG(msg) NULL @@ -730,6 +742,18 @@ pi_disconnect(PI); } +static void pd_eject( int unit ) + +{ pi_connect(PI); + pd_wait_for(unit,0,DBMSG("before unlock on eject")); + pd_send_command(unit,1,0,0,0,0,IDE_DOORUNLOCK); + pd_wait_for(unit,0,DBMSG("after unlock on eject")); + pd_wait_for(unit,0,DBMSG("before eject")); + pd_send_command(unit,0,0,0,0,0,IDE_EJECT); + pd_wait_for(unit,0,DBMSG("after eject")); + pi_disconnect(PI); +} + static void pd_media_check( int unit ) { int r; @@ -766,6 +790,8 @@ { int j; char id[PD_ID_LEN+1]; + + pd_reset(unit); pi_connect(PI); WR(0,6,0xa0); diff -ur --new-file old/linux/drivers/block/paride/pt.c new/linux/drivers/block/paride/pt.c --- old/linux/drivers/block/paride/pt.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/block/paride/pt.c Tue Feb 10 01:12:54 1998 @@ -0,0 +1,959 @@ +/* + pt.c (c) 1998 Grant R. Guenther + Under the terms of the GNU public license. + + This is the high-level driver for parallel port ATAPI tape + drives based on chips supported by the paride module. + + The driver implements both rewinding and non-rewinding + devices, filemarks, and the rewind ioctl. It allocates + a small internal "bounce buffer" for each open device, but + otherwise expects buffering and blocking to be done at the + user level. As with most block-structured tapes, short + writes are padded to full tape blocks, so reading back a file + may return more data than was actually written. + + By default, the driver will autoprobe for a single parallel + port ATAPI tape drive, but if their individual parameters are + specified, the driver can handle up to 4 drives. + + The rewinding devices are named /dev/pt0, /dev/pt1, ... + while the non-rewinding devices are /dev/npt0, /dev/npt1, etc. + + The behaviour of the pt driver can be altered by setting + some parameters from the insmod command line. The following + parameters are adjustable: + + drive0 These four arguments can be arrays of + drive1 1-6 integers as follows: + drive2 + drive3 ,,,,, + + Where, + + is the base of the parallel port address for + the corresponding drive. (required) + + is the protocol number for the adapter that + supports this drive. These numbers are + logged by 'paride' when the protocol modules + are initialised. (0 if not given) + + for those adapters that support chained + devices, this is the unit selector for the + chain of devices on the given port. It should + be zero for devices that don't support chaining. + (0 if not given) + + this can be -1 to choose the best mode, or one + of the mode numbers supported by the adapter. + (-1 if not given) + + ATAPI devices can be jumpered to master or slave. + Set this to 0 to choose the master drive, 1 to + choose the slave, -1 (the default) to choose the + first drive found. + + some parallel ports require the driver to + go more slowly. -1 sets a default value that + should work with the chosen protocol. Otherwise, + set this to a small integer, the larger it is + the slower the port i/o. In some cases, setting + this to zero will speed up the device. (default -1) + + major You may use this parameter to overide the + default major number (96) that this driver + will use. Be sure to change the device + name as well. + + name This parameter is a character string that + contains the name the kernel will use for this + device (in /proc output, for instance). + (default "pt"). + + verbose This parameter controls the amount of logging + that is done while the driver probes for + devices. Set it to 0 for a quiet load, or 1 to + see all the progress messages. (default 0) + + If this driver is built into the kernel, you can use + the following command line parameters, with the same values + as the corresponding module parameters listed above: + + pt.drive0 + pt.drive1 + pt.drive2 + pt.drive3 + + In addition, you can use the parameter pt.disable to disable + the driver entirely. + +*/ + +#define PT_VERSION "1.0" +#define PT_MAJOR 96 +#define PT_NAME "pt" +#define PT_UNITS 4 + +/* Here are things one can override from the insmod command. + Most are autoprobed by paride unless set here. Verbose is on + by default. + +*/ + +static int verbose = 0; +static int major = PT_MAJOR; +static char *name = PT_NAME; +static int disable = 0; + +static int drive0[6] = {0,0,0,-1,-1,-1}; +static int drive1[6] = {0,0,0,-1,-1,-1}; +static int drive2[6] = {0,0,0,-1,-1,-1}; +static int drive3[6] = {0,0,0,-1,-1,-1}; + +static int (*drives[4])[6] = {&drive0,&drive1,&drive2,&drive3}; +static int pt_drive_count; + +#define D_PRT 0 +#define D_PRO 1 +#define D_UNI 2 +#define D_MOD 3 +#define D_SLV 4 +#define D_DLY 5 + +#define DU (*drives[unit]) + +/* end of parameters */ + + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef MODULE + +#include "setup.h" + +static STT pt_stt[5] = {{"drive0",6,drive0}, + {"drive1",6,drive1}, + {"drive2",6,drive2}, + {"drive3",6,drive3}, + {"disable",1,&disable}}; + +void pt_setup( char *str, int *ints) + +{ generic_setup(pt_stt,5,str); +} + +#endif + +MODULE_PARM(verbose,"i"); +MODULE_PARM(major,"i"); +MODULE_PARM(name,"s"); +MODULE_PARM(drive0,"1-6i"); +MODULE_PARM(drive1,"1-6i"); +MODULE_PARM(drive2,"1-6i"); +MODULE_PARM(drive3,"1-6i"); + +#include "paride.h" + +#define PT_MAX_RETRIES 5 +#define PT_TMO 800 /* interrupt timeout in jiffies */ +#define PT_SPIN_DEL 50 /* spin delay in micro-seconds */ +#define PT_RESET_TMO 30 /* 3 seconds */ +#define PT_READY_TMO 60 /* 60 seconds */ +#define PT_REWIND_TMO 1200 /* 20 minutes */ + +#define PT_SPIN (10000/PT_SPIN_DEL)*PT_TMO + +#define STAT_ERR 0x00001 +#define STAT_INDEX 0x00002 +#define STAT_ECC 0x00004 +#define STAT_DRQ 0x00008 +#define STAT_SEEK 0x00010 +#define STAT_WRERR 0x00020 +#define STAT_READY 0x00040 +#define STAT_BUSY 0x00080 +#define STAT_SENSE 0x1f000 + +#define ATAPI_TEST_READY 0x00 +#define ATAPI_REWIND 0x01 +#define ATAPI_REQ_SENSE 0x03 +#define ATAPI_READ_6 0x08 +#define ATAPI_WRITE_6 0x0a +#define ATAPI_WFM 0x10 +#define ATAPI_IDENTIFY 0x12 +#define ATAPI_MODE_SENSE 0x1a +#define ATAPI_LOG_SENSE 0x4d + +int pt_init(void); +#ifdef MODULE +void cleanup_module( void ); +#endif + +static int pt_open(struct inode *inode, struct file *file); +static int pt_ioctl(struct inode *inode,struct file *file, + unsigned int cmd, unsigned long arg); +static int pt_release (struct inode *inode, struct file *file); +static ssize_t pt_read(struct file * filp, char * buf, + size_t count, loff_t *ppos); +static ssize_t pt_write(struct file * filp, const char * buf, + size_t count, loff_t *ppos); +static int pt_detect(void); + +static int pt_identify (int unit); + +/* bits in PT.flags */ + +#define PT_MEDIA 1 +#define PT_WRITE_OK 2 +#define PT_REWIND 4 +#define PT_WRITING 8 +#define PT_READING 16 +#define PT_EOF 32 + +#define PT_NAMELEN 8 +#define PT_BUFSIZE 16384 + +struct pt_unit { + struct pi_adapter pia; /* interface to paride layer */ + struct pi_adapter *pi; + int flags; /* various state flags */ + int last_sense; /* result of last request sense */ + int drive; /* drive */ + int access; /* count of active opens ... */ + int bs; /* block size */ + int capacity; /* Size of tape in KB */ + int present; /* device present ? */ + char *bufptr; + char name[PT_NAMELEN]; /* pf0, pf1, ... */ + }; + +struct pt_unit pt[PT_UNITS]; + +/* 'unit' must be defined in all functions - either as a local or a param */ + +#define PT pt[unit] +#define PI PT.pi + +static char pt_scratch[512]; /* scratch block buffer */ + +/* kernel glue structures */ + +static struct file_operations pt_fops = { + NULL, /* lseek - default */ + pt_read, /* read */ + pt_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select */ + pt_ioctl, /* ioctl */ + NULL, /* mmap */ + pt_open, /* open */ + pt_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* media change ? */ + NULL /* revalidate new media */ +}; + +void pt_init_units( void ) + +{ int unit, j; + + pt_drive_count = 0; + for (unit=0;unit=PT_SPIN)) { + s = RR(0,7); + e = RR(0,1); + p = RR(0,2); + if (j >= PT_SPIN) e |= 0x100; + if (fun) printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x" + " loop=%d phase=%d\n", + PT.name,fun,msg,r,s,e,j,p); + return (e<<8)+s; + } + return 0; +} + +static int pt_command( int unit, char * cmd, int dlen, char * fun ) + +{ pi_connect(PI); + + WR(0,6,DRIVE); + + if (pt_wait(unit,STAT_BUSY|STAT_DRQ,0,fun,"before command")) { + pi_disconnect(PI); + return -1; + } + + WR(0,4,dlen % 256); + WR(0,5,dlen / 256); + WR(0,7,0xa0); /* ATAPI packet command */ + + if (pt_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR,fun,"command DRQ")) { + pi_disconnect(PI); + return -1; + } + + if (RR(0,2) != 1) { + printk("%s: %s: command phase error\n",PT.name,fun); + pi_disconnect(PI); + return -1; + } + + pi_write_block(PI,cmd,12); + + return 0; +} + +static int pt_completion( int unit, char * buf, char * fun ) + +{ int r, s, n, p; + + r = pt_wait(unit,STAT_BUSY,STAT_DRQ|STAT_READY|STAT_ERR, + fun,"completion"); + + if (RR(0,7)&STAT_DRQ) { + n = (RR(0,4)+256*RR(0,5)); + p = RR(0,2)&3; + if (p == 0) pi_write_block(PI,buf,n); + if (p == 2) pi_read_block(PI,buf,n); + } + + s = pt_wait(unit,STAT_BUSY,STAT_READY|STAT_ERR,fun,"data done"); + + pi_disconnect(PI); + + return (r?r:s); +} + +static void pt_req_sense( int unit, int quiet ) + +{ char rs_cmd[12] = { ATAPI_REQ_SENSE,0,0,0,16,0,0,0,0,0,0,0 }; + char buf[16]; + int r; + + r = pt_command(unit,rs_cmd,16,"Request sense"); + udelay(1000); + if (!r) pt_completion(unit,buf,"Request sense"); + + PT.last_sense = -1; + if (!r) { + if (!quiet) printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n", + PT.name,buf[2]&0xf,buf[12],buf[13]); + PT.last_sense = (buf[2]&0xf) | ((buf[12]&0xff)<<8) + | ((buf[13]&0xff)<<16) ; + } +} + +static int pt_atapi( int unit, char * cmd, int dlen, char * buf, char * fun ) + +{ int r; + + r = pt_command(unit,cmd,dlen,fun); + udelay(1000); + if (!r) r = pt_completion(unit,buf,fun); + if (r) pt_req_sense(unit,!fun); + + return r; +} + +static void pt_sleep( int cs ) + +{ current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + cs; + schedule(); +} + +static int pt_poll_dsc( int unit, int pause, int tmo, char *msg ) + +{ int k, e, s; + + k = 0; + while (k < tmo) { + pt_sleep(pause); + k++; + pi_connect(PI); + WR(0,6,DRIVE); + s = RR(0,7); + e = RR(0,1); + pi_disconnect(PI); + if (s & (STAT_ERR|STAT_SEEK)) break; + } + if ((k >= tmo) || (s & STAT_ERR)) { + if (k >= tmo) printk("%s: %s DSC timeout\n",PT.name,msg); + else printk("%s: %s stat=0x%x err=0x%x\n",PT.name,msg,s,e); + pt_req_sense(unit,0); + return 0; + } + return 1; +} + +static void pt_media_access_cmd( int unit, int tmo, char *cmd, char *fun) + +{ if (pt_command(unit,cmd,0,fun)) { + pt_req_sense(unit,0); + return; + } + pi_disconnect(PI); + pt_poll_dsc(unit,100,tmo,fun); +} + +static void pt_rewind( int unit ) + +{ char rw_cmd[12] = {ATAPI_REWIND,0,0,0,0,0,0,0,0,0,0,0}; + + pt_media_access_cmd(unit,PT_REWIND_TMO,rw_cmd,"rewind"); +} + +static void pt_write_fm( int unit ) + +{ char wm_cmd[12] = {ATAPI_WFM,0,0,0,1,0,0,0,0,0,0,0}; + + pt_media_access_cmd(unit,PT_TMO,wm_cmd,"write filemark"); +} + +#define DBMSG(msg) NULL + +static int pt_reset( int unit ) + +{ int i, k, flg; + int expect[5] = {1,1,1,0x14,0xeb}; + long flags; + + pi_connect(PI); + WR(0,6,DRIVE); + WR(0,7,8); + + save_flags(flags); + sti(); + + pt_sleep(2); + + k = 0; + while ((k++ < PT_RESET_TMO) && (RR(1,6)&STAT_BUSY)) + pt_sleep(10); + + restore_flags(flags); + + flg = 1; + for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]); + + if (verbose) { + printk("%s: Reset (%d) signature = ",PT.name,k); + for (i=0;i<5;i++) printk("%3x",RR(0,i+1)); + if (!flg) printk(" (incorrect)"); + printk("\n"); + } + + pi_disconnect(PI); + return flg-1; +} + +static int pt_ready_wait( int unit, int tmo ) + +{ char tr_cmd[12] = {ATAPI_TEST_READY,0,0,0,0,0,0,0,0,0,0,0}; + int k, p; + + k = 0; + while (k < tmo) { + PT.last_sense = 0; + pt_atapi(unit,tr_cmd,0,NULL,DBMSG("test unit ready")); + p = PT.last_sense; + if (!p) return 0; + if (!((p == 0x010402)||((p & 0xff) == 6))) return p; + k++; + pt_sleep(100); + } + return 0x000020; /* timeout */ +} + +static void xs( char *buf, char *targ, int offs, int len ) + +{ int j,k,l; + + j=0; l=0; + for (k=0;ki_rdev); + + if ((unit >= PT_UNITS) || (!PT.present)) return -ENODEV; + + PT.access++; + + if (PT.access > 1) { + PT.access--; + return -EBUSY; + } + + MOD_INC_USE_COUNT; + + pt_identify(unit); + + if (!PT.flags & PT_MEDIA) { + PT.access--; + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + if ((!PT.flags & PT_WRITE_OK) && (file ->f_mode & 2)) { + PT.access--; + MOD_DEC_USE_COUNT; + return -EROFS; + } + + if (!(MINOR(inode->i_rdev) & 128)) + PT.flags |= PT_REWIND; + + PT.bufptr = kmalloc(PT_BUFSIZE,GFP_KERNEL); + if (PT.bufptr == NULL) { + PT.access--; + MOD_DEC_USE_COUNT; + printk("%s: buffer allocation failed\n",PT.name); + return -ENOMEM; + } + + return 0; +} + +static int pt_ioctl(struct inode *inode,struct file *file, + unsigned int cmd, unsigned long arg) +{ + int unit; + struct mtop mtop; + + if (!inode || !inode->i_rdev) + return -EINVAL; + unit = DEVICE_NR(inode->i_rdev); + if (unit >= PT_UNITS) + return -EINVAL; + if (!PT.present) + return -ENODEV; + + switch (cmd) { + case MTIOCTOP: + if (copy_from_user((char *)&mtop, (char *)arg, + sizeof(struct mtop))) return -EFAULT; + + switch (mtop.mt_op) { + + case MTREW: + pt_rewind(unit); + return 0; + + default: + printk("%s: Unimplemented mt_op %d\n",PT.name, + mtop.mt_op); + return -EINVAL; + } + + default: + printk("%s: Unimplemented ioctl 0x%x\n",PT.name,cmd); + return -EINVAL; + + } +} + + +static int pt_release (struct inode *inode, struct file *file) +{ + int unit = DEVICE_NR(inode->i_rdev); + + if ((unit >= PT_UNITS) || (PT.access <= 0)) + return -EINVAL; + + if (PT.flags & PT_WRITING) pt_write_fm(unit); + + if (PT.flags & PT_REWIND) pt_rewind(unit); + + PT.access--; + + kfree(PT.bufptr); + PT.bufptr = NULL; + + MOD_DEC_USE_COUNT; + + return 0; + +} + +static ssize_t pt_read(struct file * filp, char * buf, + size_t count, loff_t *ppos) +{ + struct inode *ino = filp->f_dentry->d_inode; + int unit = DEVICE_NR(ino->i_rdev); + char rd_cmd[12] = {ATAPI_READ_6,1,0,0,0,0,0,0,0,0,0,0}; + int k, n, r, p, s, t, b; + + if (!(PT.flags & (PT_READING|PT_WRITING))) { + PT.flags |= PT_READING; + if (pt_atapi(unit,rd_cmd,0,NULL,"start read-ahead")) + return -EIO; + } else if (PT.flags & PT_WRITING) return -EIO; + + if (PT.flags & PT_EOF) return 0; + + t = 0; + + while (count > 0) { + + if (!pt_poll_dsc(unit,1,PT_TMO,"read")) return -EIO; + + n = count; + if (n > 32768) n = 32768; /* max per command */ + b = (n-1+PT.bs)/PT.bs; + n = b*PT.bs; /* rounded up to even block */ + + rd_cmd[4] = b; + + r = pt_command(unit,rd_cmd,n,"read"); + + udelay(1000); + + if (r) { + pt_req_sense(unit,0); + return -EIO; + } + + while (1) { + + r = pt_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR|STAT_READY, + DBMSG("read DRQ"),""); + + if (r & STAT_SENSE) { + pi_disconnect(PI); + pt_req_sense(unit,0); + return -EIO; + } + + if (r) PT.flags |= PT_EOF; + + s = RR(0,7); + + if (!(s & STAT_DRQ)) break; + + n = (RR(0,4)+256*RR(0,5)); + p = (RR(0,2)&3); + if (p != 2) { + pi_disconnect(PI); + printk("%s: Phase error on read: %d\n",PT.name,p); + return -EIO; + } + + while (n > 0) { + k = n; + if (k > PT_BUFSIZE) k = PT_BUFSIZE; + pi_read_block(PI,PT.bufptr,k); + n -= k; + b = k; + if (b > count) b = count; + copy_to_user(buf+t,PT.bufptr,b); + t += b; + count -= b; + } + + } + pi_disconnect(PI); + if (PT.flags & PT_EOF) break; + } + + return t; + +} + +static ssize_t pt_write(struct file * filp, const char * buf, + size_t count, loff_t *ppos) +{ + struct inode *ino = filp->f_dentry->d_inode; + int unit = DEVICE_NR(ino->i_rdev); + char wr_cmd[12] = {ATAPI_WRITE_6,1,0,0,0,0,0,0,0,0,0,0}; + int k, n, r, p, s, t, b; + + if (!(PT.flags & PT_WRITE_OK)) return -EROFS; + + if (!(PT.flags & (PT_READING|PT_WRITING))) { + PT.flags |= PT_WRITING; + if (pt_atapi(unit,wr_cmd,0,NULL,"start buffer-available mode")) + return -EIO; + } else if (PT.flags&PT_READING) return -EIO; + + if (PT.flags & PT_EOF) return -ENOSPC; + + t = 0; + + while (count > 0) { + + if (!pt_poll_dsc(unit,1,PT_TMO,"write")) return -EIO; + + n = count; + if (n > 32768) n = 32768; /* max per command */ + b = (n-1+PT.bs)/PT.bs; + n = b*PT.bs; /* rounded up to even block */ + + wr_cmd[4] = b; + + r = pt_command(unit,wr_cmd,n,"write"); + + udelay(1000); + + if (r) { /* error delivering command only */ + pt_req_sense(unit,0); + return -EIO; + } + + while (1) { + + r = pt_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR|STAT_READY, + DBMSG("write DRQ"),NULL); + + if (r & STAT_SENSE) { + pi_disconnect(PI); + pt_req_sense(unit,0); + return -EIO; + } + + if (r) PT.flags |= PT_EOF; + + s = RR(0,7); + + if (!(s & STAT_DRQ)) break; + + n = (RR(0,4)+256*RR(0,5)); + p = (RR(0,2)&3); + if (p != 0) { + pi_disconnect(PI); + printk("%s: Phase error on write: %d \n",PT.name,p); + return -EIO; + } + + while (n > 0) { + k = n; + if (k > PT_BUFSIZE) k = PT_BUFSIZE; + b = k; + if (b > count) b = count; + copy_from_user(PT.bufptr,buf+t,b); + pi_write_block(PI,PT.bufptr,k); + t += b; + count -= b; + n -= k; + } + + } + pi_disconnect(PI); + if (PT.flags & PT_EOF) break; + } + + return t; +} + +/* end of pt.c */ + diff -ur --new-file old/linux/drivers/block/ps2esdi.c new/linux/drivers/block/ps2esdi.c --- old/linux/drivers/block/ps2esdi.c Wed May 14 07:41:05 1997 +++ new/linux/drivers/block/ps2esdi.c Tue Feb 10 01:12:54 1998 @@ -95,7 +95,7 @@ static int ps2esdi_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg); -static int ps2esdi_reread_partitions(int dev); +static int ps2esdi_reread_partitions(kdev_t dev); static int ps2esdi_read_status_words(int num_words, int max_words, u_short * buffer); @@ -1038,14 +1038,9 @@ } - static int ps2esdi_open(struct inode *inode, struct file *file) { - int dev = DEVICE_NR(MINOR(inode->i_rdev)); - -#if 0 - printk("%s: dev= %d\n", DEVICE_NAME, dev); -#endif + int dev = DEVICE_NR(inode->i_rdev); if (dev < ps2esdi_drives) { while (!ps2esdi_valid[dev]) @@ -1062,10 +1057,10 @@ static int ps2esdi_release(struct inode *inode, struct file *file) { - int dev = DEVICE_NR(MINOR(inode->i_rdev)); + int dev = DEVICE_NR(inode->i_rdev); if (dev < ps2esdi_drives) { - sync_dev(dev); + sync_dev(inode->i_rdev); access_count[dev]--; } return 0; @@ -1078,7 +1073,7 @@ { struct ps2esdi_geometry *geometry = (struct ps2esdi_geometry *) arg; - int dev = DEVICE_NR(MINOR(inode->i_rdev)), err; + int dev = DEVICE_NR(inode->i_rdev), err; if (inode && (dev < ps2esdi_drives)) switch (cmd) { @@ -1131,9 +1126,9 @@ -static int ps2esdi_reread_partitions(int dev) +static int ps2esdi_reread_partitions(kdev_t dev) { - int target = DEVICE_NR(MINOR(dev)); + int target = DEVICE_NR(dev); int start = target << ps2esdi_gendisk.minor_shift; int partition; @@ -1145,15 +1140,20 @@ for (partition = ps2esdi_gendisk.max_p - 1; partition >= 0; partition--) { - sync_dev(MAJOR_NR << 8 | start | partition); - invalidate_inodes(MAJOR_NR << 8 | start | partition); - invalidate_buffers(MAJOR_NR << 8 | start | partition); + int minor = (start | partition); + kdev_t devp = MKDEV(MAJOR_NR, minor); + struct super_block * sb = get_super(devp); + + sync_dev(devp); + if (sb) + invalidate_inodes(sb); + invalidate_buffers(devp); ps2esdi_gendisk.part[start + partition].start_sect = 0; ps2esdi_gendisk.part[start + partition].nr_sects = 0; - }; + } ps2esdi_gendisk.part[start].nr_sects = ps2esdi_info[target].head * - ps2esdi_info[target].cyl * ps2esdi_info[target].sect; + ps2esdi_info[target].cyl * ps2esdi_info[target].sect; resetup_one_dev(&ps2esdi_gendisk, target); ps2esdi_valid[target] = 1; diff -ur --new-file old/linux/drivers/block/raid5.c new/linux/drivers/block/raid5.c --- old/linux/drivers/block/raid5.c Mon Dec 22 23:15:14 1997 +++ new/linux/drivers/block/raid5.c Thu Mar 12 06:01:56 1998 @@ -837,8 +837,11 @@ struct raid5_data *raid_conf = sh->raid_conf; struct buffer_head *bh_req; - if (sh->bh_new[dd_idx]) + if (sh->bh_new[dd_idx]) { printk("raid5: bug: stripe->bh_new[%d], sector %lu exists\n", dd_idx, sh->sector); + printk("forcing oops.\n"); + *(int*)0=0; + } set_bit(BH_Lock, &bh->b_state); @@ -1372,7 +1375,7 @@ memset (raid_conf, 0, sizeof (*raid_conf)); raid_conf->mddev = mddev; - if ((raid_conf->stripe_hashtbl = (struct stripe_head **) __get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER, 0)) == NULL) + if ((raid_conf->stripe_hashtbl = (struct stripe_head **) __get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER)) == NULL) goto abort; memset(raid_conf->stripe_hashtbl, 0, HASH_PAGES * PAGE_SIZE); diff -ur --new-file old/linux/drivers/block/rd.c new/linux/drivers/block/rd.c --- old/linux/drivers/block/rd.c Mon Dec 1 19:34:11 1997 +++ new/linux/drivers/block/rd.c Wed Mar 11 20:42:30 1998 @@ -35,6 +35,9 @@ * * 4/25/96 : Made ramdisk size a parameter (default is now 4MB) * - Chad Page + * + * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98 + * */ #include @@ -344,7 +347,6 @@ struct ext2_super_block *ext2sb; struct romfs_super_block *romfsb; int nblocks = -1; - int max_blocks; unsigned char *buf; buf = kmalloc(size, GFP_KERNEL); @@ -423,17 +425,6 @@ fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE; - if ((nblocks > 0) && blk_size[MAJOR(device)]) { - max_blocks = blk_size[MAJOR(device)][MINOR(device)]; - max_blocks -= start_block; - if (nblocks > max_blocks) { - printk(KERN_NOTICE - "RAMDISK: Restricting filesystem size " - "from %d to %d blocks.\n", - nblocks, max_blocks); - nblocks = max_blocks; - } - } kfree(buf); return nblocks; } @@ -451,6 +442,7 @@ int nblocks, i; char *buf; unsigned short rotate = 0; + unsigned short devblocks = 0; char rotator[4] = { '|' , '/' , '-' , '\\' }; ram_device = MKDEV(MAJOR_NR, 0); @@ -508,8 +500,31 @@ goto done; } - printk(KERN_NOTICE "RAMDISK: Loading %d blocks into ram disk... ", nblocks); + if (blk_size[MAJOR(device)]) + devblocks = blk_size[MAJOR(device)][MINOR(device)]; + + if (devblocks == 0) { + printk(KERN_ERR "RAMDISK: could not determine device size\n"); + goto done; + } + + printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk(s)] into ram disk... ", nblocks, nblocks/devblocks+1); for (i=0; i < nblocks; i++) { + if (i && (i % devblocks == 0)) { + printk("done.\n"); + rotate = 0; + invalidate_buffers(device); + if (infile.f_op->release) + infile.f_op->release(&inode, &infile); + printk("Please insert disk #%d and press ENTER\n", i/devblocks+1); + wait_for_keypress(); + if (blkdev_open(&inode, &infile) != 0) { + printk("Error opening disk.\n"); + goto done; + } + infile.f_pos = 0; + printk("Loading disk #%d... ", i/devblocks+1); + } infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos); outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos); if (!(i % 16)) { diff -ur --new-file old/linux/drivers/block/rz1000.c new/linux/drivers/block/rz1000.c --- old/linux/drivers/block/rz1000.c Wed Dec 17 20:11:51 1997 +++ new/linux/drivers/block/rz1000.c Sat Feb 21 03:28:22 1998 @@ -15,6 +15,7 @@ #undef REALLY_SLOW_IO /* most systems can safely undef this */ +#include /* for CONFIG_BLK_DEV_IDEPCI */ #include #include #include diff -ur --new-file old/linux/drivers/cdrom/cdrom.c new/linux/drivers/cdrom/cdrom.c --- old/linux/drivers/cdrom/cdrom.c Mon Jan 5 09:06:26 1998 +++ new/linux/drivers/cdrom/cdrom.c Sun Jan 25 19:11:40 1998 @@ -1,6 +1,6 @@ /* linux/drivers/cdrom/cdrom.c. Copyright (c) 1996, 1997 David A. van Leeuwen. - Copyright (c) 1997, 1998 Erik Andersen (andersee@debian.org) + Copyright (c) 1997, 1998 Erik Andersen May be copied or modified under the terms of the GNU General Public License. See linux/COPYING for more information. @@ -10,46 +10,71 @@ The routines in the file provide a uniform interface between the software that uses CD-ROMs and the various low-level drivers that - actually talk to actual hardware devices. Suggestions are welcome. + actually talk to the hardware. Suggestions are welcome. Patches that work are more welcome though. ;-) + To Do List: + ---------------------------------- - Recent Changes: - ---------------------------------- + -- Modify sysctl/proc interface. I plan on having one directory per + drive, with entries for outputing general drive information, and sysctl + based tunable parameters such as whether the tray should auto-close for + that drive. Suggestions (or patches) for this welcome! - New maintainer! As David A. van Leeuwen has been too busy to activly + -- Change the CDROMREADMODE1, CDROMREADMODE2, CDROMREADAUDIO, and + CDROMREADRAW ioctls so they go through the Uniform CD-ROM driver. + + + + + Revision History + ---------------------------------- + 1.00 Date Unknown -- David van Leeuwen + -- Initial version by David A. van Leeuwen. I don't have a detailed + changelog for the 1.x series, David? + +2.00 Dec 2, 1997 -- Erik Andersen + -- New maintainer! As David A. van Leeuwen has been too busy to activly maintain and improve this driver, I am now carrying on the torch. If you have a problem with this driver, please feel free to contact me. - Added (rudimentary) sysctl interface. I realize this is really weak - right now, and is _very_ badly implemented. It will be improved... I - plan on having one directory per drive, with entries for outputing - general drive information, and sysctl based tunable parameters such - as whether the tray should auto-close for that drive. Suggestions (or - patches) for improvements are very welcome. + -- Added (rudimentary) sysctl interface. I realize this is really weak + right now, and is _very_ badly implemented. It will be improved... - Modified CDROM_DISC_STATUS so that it is now incorporated into + -- Modified CDROM_DISC_STATUS so that it is now incorporated into the Uniform CD-ROM driver via the cdrom_count_tracks function. The cdrom_count_tracks function helps resolve some of the false assumptions of the CDROM_DISC_STATUS ioctl, and is also used to check for the correct media type when mounting or playing audio from a CD. - Remove the calls to verify_area and only use the copy_from_user and + -- Remove the calls to verify_area and only use the copy_from_user and copy_to_user stuff, since these calls now provide their own memory checking with the 2.1.x kernels. - Major update to return codes so that errors from low-level drivers + -- Major update to return codes so that errors from low-level drivers are passed on through (thanks to Gerd Knorr for pointing out this problem). - Made it so if a function isn't implemented in a low-level driver, + -- Made it so if a function isn't implemented in a low-level driver, ENOSYS is now returned instead of EINVAL. - Simplified some complex logic so that the source code is easier to read. + -- Simplified some complex logic so that the source code is easier to read. + + -- Other stuff I probably forgot to mention (lots of changes). + +2.01 to 2.11 Dec 1997-Jan 1998 + -- TO-DO! Write changelogs for 2.01 to 2.12. - Other stuff I probably forgot to mention (lots of changes). +2.12 Jan 24, 1998 -- Erik Andersen + -- Fixed a bug in the IOCTL_IN and IOCTL_OUT macros. It turns out that + copy_*_user does not return EFAULT on error, but instead return the number + of bytes not copied. I was returning whatever non-zero stuff came back from + the copy_*_user functions directly, which would result in strange errors. - */ +-------------------------------------------------------------------------*/ + +#define REVISION "Revision: 2.12" +#define VERSION "Id: cdrom.c 2.12 1998/01/24 22:15:45 erik Exp" #include @@ -68,10 +93,6 @@ #include -#define VERSION "$Id: cdrom.c,v 2.11 1998/01/04 01:11:18 erik Exp $" -#define REVISION "Revision: 2.11" -#define FM_WRITE 0x2 /* file mode write bit */ - /* I use an error-log mask to give fine grain control over the type of error messages dumped to the system logs. The available masks include: */ #define CD_WARNING 0x1 @@ -96,15 +117,17 @@ #define cdinfo(type, fmt, args...) #endif - /* These are used to simplify getting data in from and back to user land */ #define IOCTL_IN(arg, type, in) { \ - int ret=copy_from_user(&in, (type *) arg, sizeof in); \ - if (ret) return ret; } + if ( copy_from_user(&in, (type *) arg, sizeof in) ) \ + return -EFAULT; } #define IOCTL_OUT(arg, type, out) { \ - int ret=copy_to_user((type *) arg, &out, sizeof out); \ - if (ret) return ret; } + if ( copy_to_user((type *) arg, &out, sizeof out) ) \ + return -EFAULT; } + + +#define FM_WRITE 0x2 /* file mode write bit */ /* Not-exported routines. */ static int cdrom_open(struct inode *ip, struct file *fp); diff -ur --new-file old/linux/drivers/cdrom/cdu31a.c new/linux/drivers/cdrom/cdu31a.c --- old/linux/drivers/cdrom/cdu31a.c Mon Jan 5 09:06:26 1998 +++ new/linux/drivers/cdrom/cdu31a.c Tue Feb 10 01:12:54 1998 @@ -186,6 +186,10 @@ * Heiko Eissfeldt with additional * changes by Erik Andersen * + * 24 January 1998 -- Removed the scd_disc_status() function, which was now + * just dead code left over from the port. + * Erik Andersen + * */ #include @@ -1242,33 +1246,6 @@ buf[2] = size % 256; } -/* Uniform cdrom interface function. - Return the status of the current disc: - If it is recognized as CD-I -> return XA Mode 2 Form 2 - If it is recognized as XA -> return XA Mode 2 Form 1 - If there is at least one data track return Mode 1 - else return type AUDIO - */ -static int scd_disc_status(struct cdrom_device_info *cdi) -{ - if (sony_spun_up) - { - int i; - - sony_get_toc(); - /* look into the TOC */ - if (sony_toc.disk_type == 0x10) /* this is a CD-I disc */ - return CDS_XA_2_2; - if (sony_toc.disk_type == 0x20) /* this is a XA disc */ - return CDS_XA_2_1; - for (i = 0; i < sony_toc.track_entries; i++) - if (sony_toc.tracks[i].control & CDROM_DATA_TRACK) - return CDS_DATA_1; - return CDS_AUDIO; - } else - return CDS_NO_INFO; -} - /* Starts a read operation. Returns 0 on success and 1 on failure. The read operation used here allows multiple sequential sectors to be read and status returned for each sector. The driver will @@ -3305,7 +3282,7 @@ &scd_dops, /* device operations */ NULL, /* link */ NULL, /* handle */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ @@ -3572,6 +3549,7 @@ init_timer(&cdu31a_abort_timer); cdu31a_abort_timer.function = handle_abort_timeout; + scd_info.dev = MKDEV(MAJOR_NR,0); scd_info.mask = deficiency; strncpy(scd_info.name, "cdu31a", sizeof(scd_info.name)); diff -ur --new-file old/linux/drivers/cdrom/cm206.c new/linux/drivers/cdrom/cm206.c --- old/linux/drivers/cdrom/cm206.c Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/cdrom/cm206.c Tue Feb 10 01:12:54 1998 @@ -149,6 +149,8 @@ 21 dec 1997 1.4 Upgrade to Linux 2.1.72. +24 jan 1998 Removed the cm206_disc_status() function, as it was now dead + code. The Uniform CDROM driver now provides this functionality. * * Parts of the code are based upon lmscd.c written by Kai Petzke, * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin @@ -1140,24 +1142,6 @@ return CDS_DISC_OK; } -/* gives current state of disc in drive */ -int cm206_disc_status(struct cdrom_device_info * cdi) -{ - uch xa; - get_drive_status(); - if ((cd->dsb & dsb_not_useful) | !(cd->dsb & dsb_disc_present)) - return CDS_NO_DISC; - get_disc_status(); - if (DISC_STATUS & cds_all_audio) return CDS_AUDIO; - xa = DISC_STATUS >> 4; - switch (xa) { - case 0: return CDS_DATA_1; /* can we detect CDS_DATA_2? */ - case 1: return CDS_XA_2_1; /* untested */ - case 2: return CDS_XA_2_2; - } - return 0; -} - /* locks or unlocks door lock==1: lock; return 0 upon success */ int cm206_lock_door(struct cdrom_device_info * cdi, int lock) { @@ -1264,7 +1248,7 @@ &cm206_dops, /* device operations */ NULL, /* link */ NULL, /* handle (not used by cm206) */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ @@ -1274,9 +1258,9 @@ "cm206" /* name of the device type */ }; -/* This routine gets called during initialization if thing go wrong, +/* This routine gets called during initialization if things go wrong, * can be used in cleanup_module as well. */ -void cleanup(int level) +static void cleanup(int level) { switch (level) { case 4: @@ -1402,6 +1386,7 @@ cleanup(3); return -EIO; } + cm206_info.dev = MKDEV(MAJOR_NR,0); if (register_cdrom(&cm206_info) != 0) { printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR); cleanup(3); diff -ur --new-file old/linux/drivers/cdrom/mcd.c new/linux/drivers/cdrom/mcd.c --- old/linux/drivers/cdrom/mcd.c Tue Dec 2 20:41:44 1997 +++ new/linux/drivers/cdrom/mcd.c Tue Feb 10 01:12:55 1998 @@ -216,7 +216,7 @@ &mcd_dops, /* device operations */ NULL, /* link */ NULL, /* handle */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ @@ -243,15 +243,14 @@ static int mcd_media_changed(struct cdrom_device_info * cdi, int disc_nr) { - int retval, target; + int retval; #if 1 /* the below is not reliable */ return 0; #endif - target = cdi->dev; - if (target > 0) { + if (cdi->dev) { printk("mcd: Mitsumi CD-ROM request error: invalid device.\n"); return 0; } @@ -1126,9 +1125,9 @@ -/* This routine gets called during initialization if thing go wrong, +/* This routine gets called during initialization if things go wrong, * and is used in cleanup_module as well. */ -void cleanup(int level) +static void cleanup(int level) { switch (level) { case 3: @@ -1231,17 +1230,20 @@ if (result[1] == 'D') { - sprintf(msg, " mcd: Mitsumi Double Speed CD-ROM at port=0x%x, irq=%d\n", mcd_port, mcd_irq); - MCMD_DATA_READ = MCMD_2X_READ; - mcd_info.speed = 2; - mcdDouble = 1; /* Added flag to drop to 1x speed if too many errors */ - } - else { - sprintf(msg, " mcd: Mitsumi Single Speed CD-ROM at port=0x%x, irq=%d\n", mcd_port, mcd_irq); - mcd_info.speed = 2; + sprintf(msg, " mcd: Mitsumi Double Speed CD-ROM at port=0x%x," + " irq=%d\n", mcd_port, mcd_irq); + MCMD_DATA_READ = MCMD_2X_READ; + + mcd_info.speed = 2; + /* Added flag to drop to 1x speed if too many errors */ + mcdDouble = 1; + } else { + sprintf(msg, " mcd: Mitsumi Single Speed CD-ROM at port=0x%x," + " irq=%d\n", mcd_port, mcd_irq); + mcd_info.speed = 2; } - request_region(mcd_port, 4,"mcd"); + request_region(mcd_port, 4, "mcd"); outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); outb(0x02,MCDPORT(0)); @@ -1255,6 +1257,8 @@ mcd_invalidate_buffers(); mcdPresent = 1; + + mcd_info.dev = MKDEV(MAJOR_NR,0); if (register_cdrom(&mcd_info) != 0) { printk("Cannot register Mitsumi CD-ROM!\n"); diff -ur --new-file old/linux/drivers/cdrom/mcdx.c new/linux/drivers/cdrom/mcdx.c --- old/linux/drivers/cdrom/mcdx.c Mon Jan 5 09:06:26 1998 +++ new/linux/drivers/cdrom/mcdx.c Tue Feb 10 01:12:55 1998 @@ -294,7 +294,7 @@ &mcdx_dops, /* device operations */ NULL, /* link */ NULL, /* handle */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ @@ -1024,174 +1024,186 @@ /* Support functions ************************************************/ -__initfunc(int mcdx_init(void)) +__initfunc(int mcdx_init_drive(int drive)) { - int drive; + struct s_version version; + struct s_drive_stuff* stuffp; + int size = sizeof(*stuffp); char msg[80]; -#ifdef MODULE - xwarn("Version 2.14(hs) for " UTS_RELEASE "\n"); -#else - xwarn("Version 2.14(hs) \n"); -#endif - - xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n"); - - /* zero the pointer array */ - for (drive = 0; drive < MCDX_NDRIVES; drive++) - mcdx_stuffp[drive] = NULL; - - /* do the initialisation */ - for (drive = 0; drive < MCDX_NDRIVES; drive++) { - struct s_version version; - struct s_drive_stuff* stuffp; - int size; - mcdx_blocksizes[drive] = 0; + mcdx_blocksizes[drive] = 0; - size = sizeof(*stuffp); + xtrace(INIT, "init() try drive %d\n", drive); - xtrace(INIT, "init() try drive %d\n", drive); + xtrace(INIT, "kmalloc space for stuffpt's\n"); + xtrace(MALLOC, "init() malloc %d bytes\n", size); + if (!(stuffp = kmalloc(size, GFP_KERNEL))) { + xwarn("init() malloc failed\n"); + return 1; + } - xtrace(INIT, "kmalloc space for stuffpt's\n"); - xtrace(MALLOC, "init() malloc %d bytes\n", size); - if (!(stuffp = kmalloc(size, GFP_KERNEL))) { - xwarn("init() malloc failed\n"); - break; - } + xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", + sizeof(*stuffp), stuffp); - xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp); + /* set default values */ + memset(stuffp, 0, sizeof(*stuffp)); - /* set default values */ - memset(stuffp, 0, sizeof(*stuffp)); + stuffp->present = 0; /* this should be 0 already */ + stuffp->toc = NULL; /* this should be NULL already */ - stuffp->present = 0; /* this should be 0 already */ - stuffp->toc = NULL; /* this should be NULL already */ + /* setup our irq and i/o addresses */ + stuffp->irq = irq(mcdx_drive_map[drive]); + stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); + stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; + stuffp->wreg_hcon = stuffp->wreg_reset + 1; + stuffp->wreg_chn = stuffp->wreg_hcon + 1; + + /* check if i/o addresses are available */ + if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) { + xwarn("0x%3p,%d: Init failed. " + "I/O ports (0x%3p..0x%3p) already in use.\n", + stuffp->wreg_data, stuffp->irq, + stuffp->wreg_data, + stuffp->wreg_data + MCDX_IO_SIZE - 1); + xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); + kfree(stuffp); + xtrace(INIT, "init() continue at next drive\n"); + return 0; /* next drive */ + } - /* setup our irq and i/o addresses */ - stuffp->irq = irq(mcdx_drive_map[drive]); - stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); - stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; - stuffp->wreg_hcon = stuffp->wreg_reset + 1; - stuffp->wreg_chn = stuffp->wreg_hcon + 1; - - /* check if i/o addresses are available */ - if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) { - xwarn("0x%3p,%d: " - "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n", - stuffp->wreg_data, stuffp->irq, - stuffp->wreg_data, - stuffp->wreg_data + MCDX_IO_SIZE - 1); - xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); - kfree(stuffp); - xtrace(INIT, "init() continue at next drive\n"); - continue; /* next drive */ - } - - xtrace(INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data); - - xtrace(INIT, "init() hardware reset\n"); - mcdx_reset(stuffp, HARD, 1); - - xtrace(INIT, "init() get version\n"); - if (-1 == mcdx_requestversion(stuffp, &version, 4)) { - /* failed, next drive */ - xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n", - MCDX, - stuffp->wreg_data, stuffp->irq); - xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); - kfree(stuffp); - xtrace(INIT, "init() continue at next drive\n"); - continue; - } + xtrace(INIT, "init() i/o port is available at 0x%3p\n", + stuffp->wreg_data); + xtrace(INIT, "init() hardware reset\n"); + mcdx_reset(stuffp, HARD, 1); + + xtrace(INIT, "init() get version\n"); + if (-1 == mcdx_requestversion(stuffp, &version, 4)) { + /* failed, next drive */ + xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n", + MCDX, + stuffp->wreg_data, stuffp->irq); + xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); + kfree(stuffp); + xtrace(INIT, "init() continue at next drive\n"); + return 0; + } - switch (version.code) { - case 'D': + switch (version.code) { + case 'D': stuffp->readcmd = READ2X; stuffp->present = DOUBLE | DOOR | MULTI; break; - case 'F': + case 'F': stuffp->readcmd = READ1X; stuffp->present = SINGLE | DOOR | MULTI; break; - case 'M': + case 'M': stuffp->readcmd = READ1X; stuffp->present = SINGLE; break; - default: + default: stuffp->present = 0; break; - } + } stuffp->playcmd = READ1X; + if (!stuffp->present) { + xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n", + MCDX, stuffp->wreg_data, stuffp->irq); + kfree(stuffp); + return 0; /* next drive */ + } - if (!stuffp->present) { - xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n", - MCDX, stuffp->wreg_data, stuffp->irq); - kfree(stuffp); - continue; /* next drive */ - } - - xtrace(INIT, "init() register blkdev\n"); - if (register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) { - xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n", - MCDX, - stuffp->wreg_data, stuffp->irq, MAJOR_NR); - kfree(stuffp); - continue; /* next drive */ - } - - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - read_ahead[MAJOR_NR] = READ_AHEAD; - - blksize_size[MAJOR_NR] = mcdx_blocksizes; - - xtrace(INIT, "init() subscribe irq and i/o\n"); - mcdx_irq_map[stuffp->irq] = stuffp; - if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) { - xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n", - MCDX, - stuffp->wreg_data, stuffp->irq, stuffp->irq); - stuffp->irq = 0; - kfree(stuffp); - continue; - } - request_region((unsigned int) stuffp->wreg_data, - MCDX_IO_SIZE, - "mcdx"); + xtrace(INIT, "init() register blkdev\n"); + if (register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) { + xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n", + MCDX, + stuffp->wreg_data, stuffp->irq, MAJOR_NR); + kfree(stuffp); + return 1; + } - xtrace(INIT, "init() get garbage\n"); - { - int i; - mcdx_delay(stuffp, HZ/2); - for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status); - } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = READ_AHEAD; + blksize_size[MAJOR_NR] = mcdx_blocksizes; + + xtrace(INIT, "init() subscribe irq and i/o\n"); + mcdx_irq_map[stuffp->irq] = stuffp; + if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) { + xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n", + MCDX, + stuffp->wreg_data, stuffp->irq, stuffp->irq); + stuffp->irq = 0; + kfree(stuffp); + return 0; + } + request_region((unsigned int) stuffp->wreg_data, + MCDX_IO_SIZE, + "mcdx"); + + xtrace(INIT, "init() get garbage\n"); + { + int i; + mcdx_delay(stuffp, HZ/2); + for (i = 100; i; i--) + (void) inb((unsigned int) stuffp->rreg_status); + } #if WE_KNOW_WHY - outb(0x50, (unsigned int) stuffp->wreg_chn); /* irq 11 -> channel register */ + /* irq 11 -> channel register */ + outb(0x50, (unsigned int) stuffp->wreg_chn); #endif - xtrace(INIT, "init() set non dma but irq mode\n"); - mcdx_config(stuffp, 1); + xtrace(INIT, "init() set non dma but irq mode\n"); + mcdx_config(stuffp, 1); - stuffp->minor = drive; + stuffp->minor = drive; - sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d." - " (Firmware version %c %x)\n", - stuffp->wreg_data, stuffp->irq, version.code, - version.ver); - mcdx_stuffp[drive] = stuffp; - xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); + sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d." + " (Firmware version %c %x)\n", + stuffp->wreg_data, stuffp->irq, version.code, + version.ver); + mcdx_stuffp[drive] = stuffp; + xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); + mcdx_info.dev = MKDEV(MAJOR_NR,0); if (register_cdrom(&mcdx_info) != 0) { - printk("Cannot register Mitsumi CD-ROM!\n"); - release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE); - free_irq(stuffp->irq, NULL); - kfree(stuffp); - if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) + printk("Cannot register Mitsumi CD-ROM!\n"); + release_region((unsigned long) stuffp->wreg_data, + MCDX_IO_SIZE); + free_irq(stuffp->irq, NULL); + kfree(stuffp); + if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) xwarn("cleanup() unregister_blkdev() failed\n"); - return -EIO; + return 2; } printk(msg); + return 0; +} + +__initfunc(int mcdx_init(void)) +{ + int drive; +#ifdef MODULE + xwarn("Version 2.14(hs) for " UTS_RELEASE "\n"); +#else + xwarn("Version 2.14(hs) \n"); +#endif + + xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n"); + + /* zero the pointer array */ + for (drive = 0; drive < MCDX_NDRIVES; drive++) + mcdx_stuffp[drive] = NULL; + + /* do the initialisation */ + for (drive = 0; drive < MCDX_NDRIVES; drive++) { + switch(mcdx_init_drive(drive)) { + case 2: + return -EIO; + case 1: + break; + } } return 0; } diff -ur --new-file old/linux/drivers/cdrom/sbpcd.c new/linux/drivers/cdrom/sbpcd.c --- old/linux/drivers/cdrom/sbpcd.c Mon Jan 5 09:06:26 1998 +++ new/linux/drivers/cdrom/sbpcd.c Tue Feb 10 01:12:55 1998 @@ -304,6 +304,9 @@ * Heiko Eissfeldt with additional * changes by Erik Andersen * + * 4.62 Fix a bug where playing audio left the drive in an unusable state. + * Heiko Eissfeldt + * * * TODO * implement "read all subchannel data" (96 bytes per frame) @@ -1046,7 +1049,7 @@ sbp_sleep(1); i = 1; } - msg(DBG_LCS,"CDi_stat_loop failed\n"); + msg(DBG_LCS,"CDi_stat_loop failed in line %d\n", __LINE__); return (-1); } /*==========================================================================*/ @@ -4295,7 +4298,7 @@ } if (status_tries == 0) { - msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries.\n"); + msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries in line %d.\n", __LINE__); continue; } msg(DBG_AUD,"read_audio: sbp_status: ok.\n"); @@ -4467,7 +4470,7 @@ #endif OLD_BUSY if (data_tries == 0) { - msg(DBG_AUD,"read_audio: failed after 5 tries.\n"); + msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__); RETURN_UP(-EIO); } msg(DBG_AUD,"read_audio: successful return.\n"); @@ -4651,6 +4654,7 @@ #endif SAFE_MIXED i=cc_Pause_Resume(1); D_S[d].audio_state=0; + cc_DriveReset(); RETURN_UP(i); case CDROMSTART: /* Spin up the drive */ @@ -4886,7 +4890,7 @@ } if (status_tries == 0) { - msg(DBG_INF,"sbp_status: failed after 3 tries\n"); + msg(DBG_INF,"sbp_status: failed after 3 tries in line %d\n", __LINE__); break; } @@ -5413,7 +5417,7 @@ &sbpcd_dops, /* device operations */ NULL, /* link */ NULL, /* handle */ - MKDEV(MAJOR_NR,0), /* dev */ + 0, /* dev */ 0, /* mask */ 2, /* maximum speed */ 1, /* number of discs */ diff -ur --new-file old/linux/drivers/char/ChangeLog new/linux/drivers/char/ChangeLog --- old/linux/drivers/char/ChangeLog Mon Dec 1 18:45:43 1997 +++ new/linux/drivers/char/ChangeLog Thu Mar 12 02:37:13 1998 @@ -1,3 +1,11 @@ +Thu Feb 19 14:24:08 1998 Theodore Ts'o + + * tty_io.c (tty_name): Remove the non-reentrant (and non-SMP safe) + version of tty_name, and rename the reentrant _tty_name + function to be tty_name. + (tty_open): Add a warning message stating callout devices + are deprecated. + Mon Dec 1 08:24:15 1997 Theodore Ts'o * tty_io.c (tty_get_baud_rate): Print a warning syslog if the diff -ur --new-file old/linux/drivers/char/Config.in new/linux/drivers/char/Config.in --- old/linux/drivers/char/Config.in Mon Jan 12 23:46:16 1998 +++ new/linux/drivers/char/Config.in Sat Mar 14 20:50:31 1998 @@ -89,6 +89,7 @@ bool ' Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE bool ' Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK bool ' Power off on shutdown' CONFIG_APM_POWER_OFF + bool ' Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND fi bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then @@ -109,12 +110,14 @@ bool 'Tadpole ANA H8 Support' CONFIG_H8 fi tristate 'Video For Linux' CONFIG_VIDEO_DEV -dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV -if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV - dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV +if [ "$CONFIG_VIDEO_DEV" != "n" ]; then + dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV + if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV + dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV + fi + dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV fi -dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV tristate '/dev/nvram support' CONFIG_NVRAM tristate 'PC joystick support' CONFIG_JOYSTICK bool 'Radio Device Support' CONFIG_MISC_RADIO diff -ur --new-file old/linux/drivers/char/amigamouse.c new/linux/drivers/char/amigamouse.c --- old/linux/drivers/char/amigamouse.c Sat Sep 13 20:07:27 1997 +++ new/linux/drivers/char/amigamouse.c Fri Feb 27 04:58:31 1998 @@ -44,17 +44,17 @@ #include #include #include +#include #include #include #include #include -#include #include #include -#define MSE_INT_ON() mouseint_allowed = 1 -#define MSE_INT_OFF() mouseint_allowed = 0 +#define AMI_MSE_INT_ON() mouseint_allowed = 1 +#define AMI_MSE_INT_OFF() mouseint_allowed = 0 static struct mouse_status mouse; @@ -72,7 +72,7 @@ if(!mouseint_allowed) return; - MSE_INT_OFF(); + AMI_MSE_INT_OFF(); /* * This routine assumes, just like Kickstart, that the mouse @@ -156,7 +156,7 @@ if (mouse.fasyncptr) kill_fasync(mouse.fasyncptr, SIGIO); } - MSE_INT_ON(); + AMI_MSE_INT_ON(); } static int fasync_mouse(struct file *filp, int on) @@ -178,7 +178,7 @@ if (--mouse.active) return 0; free_irq(IRQ_AMIGA_VERTB, mouse_interrupt); - MSE_INT_OFF(); + AMI_MSE_INT_OFF(); MOD_DEC_USE_COUNT; return 0; } @@ -211,7 +211,7 @@ mouse.buttons = 0x87; mouse.active = 1; MOD_INC_USE_COUNT; - MSE_INT_ON(); + AMI_MSE_INT_ON(); return 0; } @@ -219,8 +219,8 @@ * writes are disallowed */ -static long write_mouse(struct inode * inode, struct file * file, - const char * buffer, unsigned long count) +static ssize_t write_mouse(struct file * file, const char * buffer, + size_t count, loff_t *ppos) { return -EINVAL; } @@ -229,18 +229,15 @@ * read mouse data. Currently never blocks. */ -static long read_mouse(struct inode * inode, struct file * file, - char * buffer, unsigned long count) +static ssize_t read_mouse(struct file * file, char * buffer, + size_t count, loff_t *ppos) { - int r; int dx; int dy; unsigned char buttons; if (count < 3) return -EINVAL; - if ((r = verify_area(VERIFY_WRITE, buffer, count))) - return r; if (!mouse.ready) return -EAGAIN; @@ -251,7 +248,7 @@ * so paging in put_user() does not effect mouse tracking. */ - MSE_INT_OFF(); + AMI_MSE_INT_OFF(); dx = mouse.dx; dy = mouse.dy; if (dx < -127) @@ -268,14 +265,17 @@ mouse.dx -= dx; mouse.dy -= dy; mouse.ready = 0; - MSE_INT_ON(); + AMI_MSE_INT_ON(); - put_user(buttons | 0x80, buffer); - put_user((char)dx, buffer + 1); - put_user((char)dy, buffer + 2); - for (r = 3; r < count; r++) - put_user(0x00, buffer + r); - return r; + if ((put_user(buttons | 0x80, buffer++)) || + put_user((char)dx, buffer++) || + put_user((char)dy, buffer++)) + return -EINVAL; + + if (count > 3) + if (clear_user(buffer, count - 3)) + return -EFAULT; + return count; } /* @@ -284,7 +284,7 @@ static unsigned int mouse_poll(struct file *file, poll_table * wait) { - poll_wait(&mouse.wait, wait); + poll_wait(file, &mouse.wait, wait); if (mouse.ready) return POLLIN | POLLRDNORM; return 0; @@ -315,7 +315,7 @@ custom.joytest = 0; /* reset counters */ - MSE_INT_OFF(); + AMI_MSE_INT_OFF(); mouse.active = 0; mouse.ready = 0; diff -ur --new-file old/linux/drivers/char/apm_bios.c new/linux/drivers/char/apm_bios.c --- old/linux/drivers/char/apm_bios.c Mon Dec 22 02:41:24 1997 +++ new/linux/drivers/char/apm_bios.c Thu Mar 12 00:10:39 1998 @@ -26,6 +26,8 @@ * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au) * Version 1.0 and 1.1 * May 1996, Version 1.2 + * Feb 1998, Version 1.3 + * Feb 1998, Version 1.4 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -44,8 +46,12 @@ * levels to the printk calls. APM is not defined for SMP machines. * The new replacment for it is, but Linux doesn't yet support this. * Alan Cox Linux 2.1.55 + * 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's + * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by + * Dean Gaudet . + * C. Scott Ananian Linux 2.1.87 * - * Reference: + * APM 1.1 Reference: * * Intel Corporation, Microsoft Corporation. Advanced Power Management * (APM) BIOS Interface Specification, Revision 1.1, September 1993. @@ -56,6 +62,15 @@ * ftp://ftp.intel.com/pub/IAL/software_specs/apmv11.doc. It is also * available from Microsoft by calling 206.882.8080.] * + * APM 1.2 Reference: + * Intel Corporation, Microsoft Corporation. Advanced Power Management + * (APM) BIOS Interface Specification, Revision 1.2, February 1996. + * + * [This document is available from Intel at: + * http://www.intel.com/IAL/powermgm + * or Microsoft at + * http://www.microsoft.com/windows/thirdparty/hardware/pcfuture.htm + * ] */ #include @@ -126,6 +141,11 @@ * problems have been reported when using this option with gpm (if you'd * like to debug this, please do so). * + * CONFIG_APM_IGNORE_MULTIPLE_SUSPEND: The IBM TP560 bios seems to insist + * on returning multiple suspend/standby events whenever one occurs. We + * really only need one at a time, so just ignore any beyond the first. + * This is probably safe on most laptops. + * * If you are debugging the APM support for your laptop, note that code for * all of these options is contained in this file, so you can #define or * #undef these on the next line to avoid recompiling the whole kernel. @@ -139,6 +159,8 @@ * U: ACER 486DX4/75: uses dseg 0040, in violation of APM specification * [Confirmed by BIOS disassembly] * P: Toshiba 1950S: battery life information only gets updated after resume + * P: Midwest Micro Soundbook Elite DX2/66 monochrome: screen blanking + * broken in BIOS [Reported by Garst R. Reese ] * * Legend: U = unusable with APM patches * P = partially usable with APM patches @@ -162,8 +184,8 @@ #define APM_NOINTS /* - * Define to make the APM BIOS calls zero all data segment registers (do - * that if an incorrect BIOS implementation will cause a kernel panic if it + * Define to make the APM BIOS calls zero all data segment registers (so + * that an incorrect BIOS implementation will cause a kernel panic if it * tries to write to arbitrary memory). */ #define APM_ZERO_SEGS @@ -277,9 +299,15 @@ : "a" (0x530a), "b" (1) \ APM_BIOS_CALL_END -#define APM_GET_EVENT(event, error) \ +#define APM_GET_BATTERY_STATUS(which, bx, cx, dx, si, error) \ + APM_BIOS_CALL(al) \ + : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx), "=S" (si) \ + : "a" (0x530a), "b" (0x8000 | (which)) \ + APM_BIOS_CALL_END + +#define APM_GET_EVENT(event, info, error) \ APM_BIOS_CALL(al) \ - : "=a" (error), "=b" (event) \ + : "=a" (error), "=b" (event), "=c" (info) \ : "a" (0x530b) \ APM_BIOS_CALL_END @@ -331,6 +359,9 @@ #endif static int suspends_pending = 0; static int standbys_pending = 0; +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND +static int waiting_for_resume = 0; +#endif static long clock_cmos_diff; static int got_clock_diff = 0; @@ -340,7 +371,7 @@ static struct timer_list apm_timer; -static char driver_version[] = "1.2";/* no spaces */ +static char driver_version[] = "1.4"; /* no spaces */ #ifdef APM_DEBUG static char * apm_event_name[] = { @@ -354,7 +385,8 @@ "critical suspend", "user standby", "user suspend", - "system standby resume" + "system standby resume", + "capabilities change" }; #define NR_APM_EVENT_NAME \ (sizeof(apm_event_name) / sizeof(apm_event_name[0])) @@ -404,6 +436,8 @@ { APM_BAD_DEVICE, "Unrecognized device ID" }, { APM_BAD_PARAM, "Parameter out of range" }, { APM_NOT_ENGAGED, "Interface not engaged" }, + { APM_BAD_FUNCTION, "Function not supported" }, + { APM_RESUME_DISABLED, "Resume timer disabled" }, { APM_BAD_STATE, "Unable to enter requested state" }, /* N/A { APM_NO_EVENTS, "No events pending" }, */ { APM_NOT_PRESENT, "No APM present" } @@ -421,13 +455,15 @@ return APM_SUCCESS; } -static int apm_get_event(apm_event_t *event) +static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info) { u_short error; - APM_GET_EVENT(*event, error); + APM_GET_EVENT(*event, *info, error); if (error & 0xff) return (error >> 8); + if (apm_bios_info.version < 0x0102) + *info = ~0; /* indicate info not valid */ return APM_SUCCESS; } @@ -479,6 +515,24 @@ return APM_SUCCESS; } +static int apm_get_battery_status(u_short which, + u_short *bat, u_short *life, u_short *nbat) +{ + u_short status, error; + + if (apm_bios_info.version < 0x0102) { + /* pretend we only have one battery. */ + if (which!=1) return APM_BAD_DEVICE; + *nbat = 1; + return apm_get_power_status(&status, bat, life); + } + + APM_GET_BATTERY_STATUS(which, status, *bat, *life, *nbat, error); + if (error & 0xff) + return (error >> 8); + return APM_SUCCESS; +} + static inline int apm_engage_power_management(u_short device) { u_short error; @@ -581,8 +635,15 @@ if (as == sender) continue; as->event_head = (as->event_head + 1) % APM_MAX_EVENTS; - if (as->event_head == as->event_tail) + if (as->event_head == as->event_tail) { + static int notified; + + if (notified == 0) { + printk( "apm_bios: an event queue overflowed\n" ); + notified = 1; + } as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + } as->events[as->event_head] = event; if (!as->suser) continue; @@ -650,10 +711,12 @@ { int error; apm_event_t event; + apm_eventinfo_t info; static int notified = 0; - error = apm_get_event(&event); + /* we don't use the eventinfo */ + error = apm_get_event(&event, &info); if (error == APM_SUCCESS) return event; @@ -687,9 +750,23 @@ apm_event_t event; while ((event = get_event()) != 0) { +#ifdef APM_DEBUG + if (event <= NR_APM_EVENT_NAME) + printk(KERN_DEBUG "APM BIOS received %s notify\n", + apm_event_name[event - 1]); + else + printk(KERN_DEBUG "APM BIOS received unknown " + "event 0x%02x\n", event); +#endif switch (event) { case APM_SYS_STANDBY: case APM_USER_STANDBY: +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + if (waiting_for_resume) { + return; + } + waiting_for_resume = 1; +#endif send_event(event, APM_STANDBY_RESUME, NULL); if (standbys_pending <= 0) standby(); @@ -702,6 +779,12 @@ break; #endif case APM_SYS_SUSPEND: +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + if (waiting_for_resume) { + return; + } + waiting_for_resume = 1; +#endif send_event(event, APM_NORMAL_RESUME, NULL); if (suspends_pending <= 0) suspend(); @@ -710,12 +793,16 @@ case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: case APM_STANDBY_RESUME: +#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND + waiting_for_resume = 0; +#endif set_time(); send_event(event, 0, NULL); break; case APM_LOW_BATTERY: case APM_POWER_STATUS_CHANGE: + case APM_CAPABILITY_CHANGE: send_event(event, 0, NULL); break; @@ -727,14 +814,6 @@ suspend(); break; } -#ifdef APM_DEBUG - if (event <= NR_APM_EVENT_NAME) - printk(KERN_DEBUG "APM BIOS received %s notify\n", - apm_event_name[event - 1]); - else - printk(KERN_DEBUG "APM BIOS received unknown event 0x%02x\n", - event); -#endif } } @@ -869,7 +948,7 @@ as = fp->private_data; if (check_apm_bios_struct(as, "select")) return 0; - poll_wait(&process_list, wait); + poll_wait(fp, &process_list, wait); if (!queue_empty(as)) return POLLIN | POLLRDNORM; return 0; @@ -1104,22 +1183,37 @@ if (apm_bios_info.version == 0x001) apm_bios_info.version = 0x100; + /* BIOS < 1.2 doesn't set cseg_16_len */ + if (apm_bios_info.version < 0x102) + apm_bios_info.cseg_16_len = 0xFFFF; /* 64k */ + printk(KERN_INFO " Entry %x:%lx cseg16 %x dseg %x", apm_bios_info.cseg, apm_bios_info.offset, apm_bios_info.cseg_16, apm_bios_info.dseg); if (apm_bios_info.version > 0x100) - printk(" cseg len %x, dseg len %x", - apm_bios_info.cseg_len, apm_bios_info.dseg_len); + printk(" cseg len %x, cseg16 len %x, dseg len %x", + apm_bios_info.cseg_len, apm_bios_info.cseg_16_len, + apm_bios_info.dseg_len); printk("\n"); + /* + * Set up a segment that references the real mode segment 0x40 + * that extends up to the end of page zero (that we have reserved). + * This is for buggy BIOS's that refer to (real mode) segment 0x40 + * even though they are called in protected mode. + */ + set_base(gdt[APM_40 >> 3], + __va((unsigned long)0x40 << 4)); + set_limit(gdt[APM_40 >> 3], 4096 - (0x40 << 4)); + apm_bios_entry.offset = apm_bios_info.offset; apm_bios_entry.segment = APM_CS; set_base(gdt[APM_CS >> 3], - 0xc0000000 + ((unsigned long)apm_bios_info.cseg << 4)); + __va((unsigned long)apm_bios_info.cseg << 4)); set_base(gdt[APM_CS_16 >> 3], - 0xc0000000 + ((unsigned long)apm_bios_info.cseg_16 << 4)); + __va((unsigned long)apm_bios_info.cseg_16 << 4)); set_base(gdt[APM_DS >> 3], - 0xc0000000 + ((unsigned long)apm_bios_info.dseg << 4)); + __va((unsigned long)apm_bios_info.dseg << 4)); if (apm_bios_info.version == 0x100) { set_limit(gdt[APM_CS >> 3], 64 * 1024); set_limit(gdt[APM_CS_16 >> 3], 64 * 1024); @@ -1134,19 +1228,25 @@ set_limit(gdt[APM_DS >> 3], 64 * 1024); #else set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len); - set_limit(gdt[APM_CS_16 >> 3], 64 * 1024); + set_limit(gdt[APM_CS_16 >> 3], apm_bios_info.cseg_16_len); set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len); #endif - apm_bios_info.version = 0x0101; + /* The APM 1.2 docs state that the apm_driver_version + * call can fail if we try to connect as 1.2 to a 1.1 bios. + */ + apm_bios_info.version = 0x0102; error = apm_driver_version(&apm_bios_info.version); - if (error != 0) + if (error != 0) { /* Fall back to an APM 1.1 connection. */ + apm_bios_info.version = 0x0101; + error = apm_driver_version(&apm_bios_info.version); + } + if (error != 0) /* Fall back to an APM 1.0 connection. */ apm_bios_info.version = 0x100; else { apm_engage_power_management(0x0001); printk( " Connection version %d.%d\n", (apm_bios_info.version >> 8) & 0xff, apm_bios_info.version & 0xff ); - apm_bios_info.version = 0x0101; } } diff -ur --new-file old/linux/drivers/char/atarimouse.c new/linux/drivers/char/atarimouse.c --- old/linux/drivers/char/atarimouse.c Sat Sep 13 20:07:27 1997 +++ new/linux/drivers/char/atarimouse.c Fri Feb 27 04:58:52 1998 @@ -90,14 +90,14 @@ return 0; } -static long write_mouse(struct inode *inode, struct file *file, - const char *buffer, unsigned long count) +static ssize_t write_mouse(struct file *file, const char *buffer, + size_t count, loff_t *ppos) { return -EINVAL; } -static long read_mouse(struct inode *inode, struct file *file, - char *buffer, unsigned long count) +static ssize_t read_mouse(struct file * file, char * buffer, + size_t count, loff_t *ppos) { int dx, dy, buttons; @@ -134,7 +134,7 @@ static unsigned int mouse_poll(struct file *file, poll_table *wait) { - poll_wait(&mouse.wait, wait); + poll_wait(file, &mouse.wait, wait); if (mouse.ready) return POLLIN | POLLRDNORM; return 0; diff -ur --new-file old/linux/drivers/char/atixlmouse.c new/linux/drivers/char/atixlmouse.c --- old/linux/drivers/char/atixlmouse.c Thu Nov 13 05:28:26 1997 +++ new/linux/drivers/char/atixlmouse.c Fri Feb 27 04:59:02 1998 @@ -176,7 +176,7 @@ static unsigned int mouse_poll(struct file *file, poll_table * wait) { - poll_wait(&mouse.wait, wait); + poll_wait(file, &mouse.wait, wait); if (mouse.ready) return POLLIN | POLLRDNORM; return 0; diff -ur --new-file old/linux/drivers/char/bttv.c new/linux/drivers/char/bttv.c --- old/linux/drivers/char/bttv.c Mon Jan 12 23:46:27 1998 +++ new/linux/drivers/char/bttv.c Sat Feb 21 03:28:22 1998 @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -129,16 +128,22 @@ btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C); - - for (i=0x7fffffff; i; i--) + + /* + * Timeout for I2CRead is 1 second (this should be enough, really!) + */ + for (i=1000; i; i--) { stat=btread(BT848_INT_STAT); if (stat & BT848_INT_I2CDONE) break; + udelay(1000); /* 1ms, as I2C is 1kHz (?) */ } - if (!i) + if (!i) { + printk(KERN_DEBUG "bttv: I2CRead timeout\n"); return -1; + } if (!(stat & BT848_INT_RACK)) return -2; @@ -167,15 +172,18 @@ btwrite(data, BT848_I2C); - for (i=0x7fffffff; i; i--) + for (i=1000; i; i--) { stat=btread(BT848_INT_STAT); if (stat & BT848_INT_I2CDONE) break; + udelay(1000); } - if (!i) + if (!i) { + printk(KERN_DEBUG "bttv: I2CWrite timeout\n"); return -1; + } if (!(stat & BT848_INT_RACK)) return -2; @@ -772,7 +780,7 @@ /* * 32bit depth frame buffers need extra flags setting */ - + if (depth==4) mask=BT848_RISC_BYTE3; else @@ -1093,13 +1101,13 @@ case VIDIOCGPICT: { struct video_picture p=btv->picture; - if(btv->win.bpp==8) + if(btv->win.bpp==1) p.palette=VIDEO_PALETTE_HI240; - if(btv->win.bpp==16) + if(btv->win.bpp==2) p.palette=VIDEO_PALETTE_RGB565; - if(btv->win.bpp==24) + if(btv->win.bpp==3) p.palette=VIDEO_PALETTE_RGB24; - if(btv->win.bpp==32) + if(btv->win.bpp==4) p.palette=VIDEO_PALETTE_RGB32; if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; @@ -1288,11 +1296,10 @@ struct video_audio v; if(copy_from_user(&v,arg, sizeof(v))) return -EFAULT; + if(v.audio!=0) + return -EINVAL; if(v.flags&VIDEO_AUDIO_MUTE) audio(btv, AUDIO_MUTE); - if(v.audio<0||v.audio>2) - return -EINVAL; - bt848_muxsel(btv,v.audio); if(!(v.flags&VIDEO_AUDIO_MUTE)) audio(btv, AUDIO_UNMUTE); btv->audio_dev=v; @@ -1478,7 +1485,20 @@ unsigned char bus, devfn; unsigned char b, bo; - /* nothing wrong with this one, just checking buffer control config */ + /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ + + if (!pcibios_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, index, &bus, &devfn)) + { + printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); + } + + if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, + index, &bus, &devfn)) + { + pcibios_read_config_byte(bus, devfn, 0x53, &b); + DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); + DEBUG(printk("bufcon=0x%02x\n",b)); + } if (!pcibios_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, index, &bus, &devfn)) @@ -1663,7 +1683,7 @@ return -1; if (!(btv->risc_even=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; - if (!(btv->risc_jmp =(dword *) kmalloc(1024, GFP_KERNEL))) + if (!(btv->risc_jmp =(dword *) kmalloc(2048, GFP_KERNEL))) return -1; btv->vbi_odd=btv->risc_jmp+12; btv->vbi_even=btv->vbi_odd+256; diff -ur --new-file old/linux/drivers/char/busmouse.c new/linux/drivers/char/busmouse.c --- old/linux/drivers/char/busmouse.c Tue Nov 4 00:14:20 1997 +++ new/linux/drivers/char/busmouse.c Fri Feb 27 04:59:20 1998 @@ -109,7 +109,6 @@ static int fasync_mouse(struct file *filp, int on) { int retval; - struct inode *inode = filp->f_dentry->d_inode; retval = fasync_helper(filp, on, &mouse.fasyncptr); if (retval < 0) @@ -224,7 +223,7 @@ */ static unsigned int mouse_poll(struct file *file, poll_table * wait) { - poll_wait(&mouse.wait, wait); + poll_wait(file, &mouse.wait, wait); if (mouse.ready) return POLLIN | POLLRDNORM; return 0; 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 Mon Jan 12 23:46:16 1998 +++ new/linux/drivers/char/bw-qcam.c Sat Feb 21 03:28:22 1998 @@ -43,7 +43,6 @@ ******************************************************************/ #include -#include #include #include #include @@ -923,11 +922,12 @@ close_bwqcam(qcams[i]); } #else -__initfunc(int init_bwqcams(struct video_init *unused)) +__initfunc(int init_bw_qcams(struct video_init *unused)) { struct parport *port; for (port = parport_enumerate(); port; port=port->next) init_bwqcam(port); + return 0; } #endif diff -ur --new-file old/linux/drivers/char/c-qcam.c new/linux/drivers/char/c-qcam.c --- old/linux/drivers/char/c-qcam.c Mon Jan 12 23:46:16 1998 +++ new/linux/drivers/char/c-qcam.c Sat Feb 21 03:28:22 1998 @@ -9,7 +9,6 @@ #include -#include #include #include #include @@ -771,5 +770,6 @@ for (port = parport_enumerate(); port; port=port->next) init_cqcam(port); + return 0; } #endif diff -ur --new-file old/linux/drivers/char/cd1865.h new/linux/drivers/char/cd1865.h --- old/linux/drivers/char/cd1865.h Tue Dec 2 18:19:03 1997 +++ new/linux/drivers/char/cd1865.h Thu Mar 5 20:55:06 1998 @@ -3,7 +3,7 @@ * for the Specialix IO8+ multiport serial driver. * * Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl) - * Copyright (C) 1994-1996 Dmitry Gorodchanin (begemot@bgm.rosprint.net) + * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com) * * Specialix pays for the development and support of this driver. * Please DO contact io8-linux@specialix.co.uk if you require diff -ur --new-file old/linux/drivers/char/conmakehash.c new/linux/drivers/char/conmakehash.c --- old/linux/drivers/char/conmakehash.c Tue Aug 12 02:28:19 1997 +++ new/linux/drivers/char/conmakehash.c Tue Feb 10 01:12:55 1998 @@ -283,7 +283,7 @@ } printf("0x%04x", unitable[fp0][nent++]); if ( i == nuni-1 ) - printf("\n};"); + printf("\n};\n"); else if ( i % 8 == 7 ) printf(",\n\t"); else diff -ur --new-file old/linux/drivers/char/console.c new/linux/drivers/char/console.c --- old/linux/drivers/char/console.c Thu Dec 4 00:21:57 1997 +++ new/linux/drivers/char/console.c Tue Feb 10 01:12:55 1998 @@ -1420,6 +1420,12 @@ /* If we got -4 (not found) then see if we have defined a replacement character (U+FFFD) */ tc = conv_uni_to_pc(0xfffd); + + /* One reason for the -4 can be that we just + did a clear_unimap(); + try at least to show something. */ + if (tc == -4) + tc = c; } else if ( tc == -3 ) { /* Bad hash table -- hope for the best */ tc = c; diff -ur --new-file old/linux/drivers/char/dsp56k.c new/linux/drivers/char/dsp56k.c --- old/linux/drivers/char/dsp56k.c Tue Jun 17 01:35:55 1997 +++ new/linux/drivers/char/dsp56k.c Sat Feb 21 03:28:22 1998 @@ -23,7 +23,6 @@ * for more details. */ -#include #include #include #include /* for kmalloc() and kfree() */ @@ -207,9 +206,10 @@ return 0; } -static long dsp56k_read(struct inode *inode, struct file *file, - char *buf, unsigned long count) +static ssize_t dsp56k_read(struct file *file, char *buf, size_t count, + loff_t *ppos) { + struct inode *inode = file->f_dentry->d_inode; int dev = MINOR(inode->i_rdev) & 0x0f; switch(dev) @@ -269,9 +269,10 @@ } } -static long dsp56k_write(struct inode *inode, struct file *file, - const char *buf, unsigned long count) +static ssize_t dsp56k_write(struct file *file, const char *buf, size_t count, + loff_t *ppos) { + struct inode *inode = file->f_dentry->d_inode; int dev = MINOR(inode->i_rdev) & 0x0f; switch(dev) @@ -425,7 +426,7 @@ * but how do I then check device minor number? * Do I need this function at all??? */ -#ifdef 0 +#if 0 static int dsp56k_select(struct inode *inode, struct file *file, int sel_type, select_table *wait) { diff -ur --new-file old/linux/drivers/char/epca.c new/linux/drivers/char/epca.c --- old/linux/drivers/char/epca.c Sat Sep 20 23:51:54 1997 +++ new/linux/drivers/char/epca.c Wed Feb 25 07:08:01 1998 @@ -29,8 +29,10 @@ #ifdef MODVERSIONS +#ifndef MODULE #define MODULE #endif +#endif /* ----------------------------------------------------------------------- This way modules should work regardless if they defined MODULE or @@ -183,7 +185,7 @@ /* ---------------------------------------------------------------------- Begin generic memory functions. These functions will be alias - (point at) more specific functions dependant on the board being + (point at) more specific functions dependent on the board being configured. ----------------------------------------------------------------------- */ @@ -459,7 +461,7 @@ cards (Such as PCI) needs no windowing routines at all. We provide these do nothing routines so that the same code base can be used. The driver will ALWAYS call a windowing routine if it thinks it needs - to; regardless of the card. However, dependant on the card the routine + to; regardless of the card. However, dependent on the card the routine may or may not do anything. ---------------------------------------------------------------------------*/ @@ -4064,7 +4066,7 @@ base_addr5); /* ------------------------------------------------------------------------ - NOTE - The code below mask out either the 2 or 4 bits dependant on the + NOTE - The code below mask out either the 2 or 4 bits dependent on the space being addressed. (base_addr value reflecting io space, have their first 2 bits mask out, while base_addr value reflecting mem space, have their first 4 bits mask out.) These bits are flag bits and should always diff -ur --new-file old/linux/drivers/char/esp.c new/linux/drivers/char/esp.c --- old/linux/drivers/char/esp.c Mon Dec 1 18:45:43 1997 +++ new/linux/drivers/char/esp.c Thu Mar 12 02:37:13 1998 @@ -29,9 +29,8 @@ * by Chris Faylor. * * Most recent changes: (Andrew J. Robinson) - * Added rx_trigger, tx_trigger, flow_off, flow_on, and rx_timeout options. - * ESP enhanced mode configuration can be viewed/changed by a patched - * version of setserial. + * Support for PIO mode. This allows the driver to work properly with + * multiport cards. * * This module exports the following rs232 io functions: * @@ -94,13 +93,14 @@ static char *dma_buffer; static int dma_bytes; +static struct esp_pio_buffer *free_pio_buf; #define DMA_BUFFER_SZ 1024 #define WAKEUP_CHARS 1024 static char *serial_name = "ESP serial driver"; -static char *serial_version = "1.6"; +static char *serial_version = "2.0"; static DECLARE_TASK_QUEUE(tq_esp); @@ -135,7 +135,7 @@ #define DBG_CNT(s) #endif -static struct esp_struct *IRQ_ports[16]; +static struct esp_struct *ports; static void change_speed(struct esp_struct *info); static void rs_wait_until_sent(struct tty_struct *, int); @@ -290,181 +290,249 @@ queue_task(&info->tqueue, &tq_esp); mark_bh(ESP_BH); } - -static void receive_chars_dma(struct esp_struct *info) +static _INLINE_ struct esp_pio_buffer *get_pio_buffer(void) { - info->stat_flags &= ~(ESP_STAT_RX_TIMEOUT | ESP_STAT_NEED_DMA_RX); + struct esp_pio_buffer *buf; - serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); - serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL); - dma_bytes = serial_in(info, UART_ESI_STAT1) << 8; - dma_bytes |= serial_in(info, UART_ESI_STAT2); + if (free_pio_buf) { + buf = free_pio_buf; + free_pio_buf = buf->next; + } else { + buf = (struct esp_pio_buffer *) + kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC); + } - if (!dma_bytes) - return; - - info->stat_flags |= ESP_STAT_DMA_RX; - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma, DMA_MODE_READ); - set_dma_addr(dma, virt_to_bus(dma_buffer)); - set_dma_count(dma, dma_bytes); - enable_dma(dma); - serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); + return buf; } -static void do_ttybuf(void *private_) +static _INLINE_ void release_pio_buffer(struct esp_pio_buffer *buf) { - struct esp_struct *info = (struct esp_struct *) private_; - struct tty_struct *tty; - int avail_bytes, x_bytes; - unsigned long int flags; + buf->next = free_pio_buf; + free_pio_buf = buf; +} - save_flags(flags); cli(); +static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes) +{ + struct tty_struct *tty = info->tty; + int i; + struct esp_pio_buffer *pio_buf; + struct esp_pio_buffer *err_buf; + unsigned char status_mask; + + pio_buf = get_pio_buffer(); + + if (!pio_buf) + return; + + err_buf = get_pio_buffer(); + + if (!err_buf) { + release_pio_buffer(pio_buf); + return; + } + + sti(); + + status_mask = (info->read_status_mask >> 2) & 0x07; + + for (i = 0; i < num_bytes - 1; i += 2) { + *((unsigned short *)(pio_buf->data + i)) = + inw(info->port + UART_ESI_RX); + err_buf->data[i] = serial_in(info, UART_ESI_RWS); + err_buf->data[i + 1] = (err_buf->data[i] >> 3) & status_mask; + err_buf->data[i] &= status_mask; + } + + if (num_bytes & 0x0001) { + pio_buf->data[num_bytes - 1] = serial_in(info, UART_ESI_RX); + err_buf->data[num_bytes - 1] = + (serial_in(info, UART_ESI_RWS) >> 3) & status_mask; + } + + cli(); + + /* make sure everything is still ok since interrupts were enabled */ tty = info->tty; if (!tty) { - restore_flags(flags); + release_pio_buffer(pio_buf); + release_pio_buffer(err_buf); + info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; return; } - avail_bytes = TTY_FLIPBUF_SIZE - tty->flip.count; + status_mask = (info->ignore_status_mask >> 2) & 0x07; - if (avail_bytes) { - if (info->tty_buf->count < avail_bytes) - x_bytes = info->tty_buf->count; - else - x_bytes = avail_bytes; + for (i = 0; i < num_bytes; i++) { + if (!(err_buf->data[i] & status_mask)) { + *(tty->flip.char_buf_ptr++) = pio_buf->data[i]; - tty->flip.count += x_bytes; - memcpy(tty->flip.char_buf_ptr, info->tty_buf->char_buf, - x_bytes); - memcpy(tty->flip.flag_buf_ptr, info->tty_buf->flag_buf, - x_bytes); - tty->flip.char_buf_ptr += x_bytes; - tty->flip.flag_buf_ptr += x_bytes; - info->tty_buf->count -= x_bytes; - info->tty_buf->char_buf_ptr -= x_bytes; - info->tty_buf->flag_buf_ptr -= x_bytes; - - if (info->tty_buf->count) { - memmove(info->tty_buf->char_buf, - info->tty_buf->char_buf + x_bytes, - info->tty_buf->count); - queue_task(&info->tty_buf->tqueue, - &tq_timer); - } + if (err_buf->data[i] & 0x04) { + *(tty->flip.flag_buf_ptr++) = TTY_BREAK; - queue_task(&tty->flip.tqueue, &tq_timer); - } else { - queue_task(&info->tty_buf->tqueue, &tq_timer); + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } + else if (err_buf->data[i] & 0x02) + *(tty->flip.flag_buf_ptr++) = TTY_FRAME; + else if (err_buf->data[i] & 0x01) + *(tty->flip.flag_buf_ptr++) = TTY_PARITY; + else + *(tty->flip.flag_buf_ptr++) = 0; + + tty->flip.count++; + } } - restore_flags(flags); + queue_task(&tty->flip.tqueue, &tq_timer); + + info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; + release_pio_buffer(pio_buf); + release_pio_buffer(err_buf); +} + +static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes) +{ + info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; + dma_bytes = num_bytes; + info->stat_flags |= ESP_STAT_DMA_RX; + disable_dma(dma); + clear_dma_ff(dma); + set_dma_mode(dma, DMA_MODE_READ); + set_dma_addr(dma, virt_to_bus(dma_buffer)); + set_dma_count(dma, dma_bytes); + enable_dma(dma); + serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); } static _INLINE_ void receive_chars_dma_done(struct esp_struct *info, int status) { struct tty_struct *tty = info->tty; - int num_bytes, bytes_left, x_bytes; - struct tty_flip_buffer *buffer; - - if (!(info->stat_flags & ESP_STAT_DMA_RX)) - return; + int num_bytes; disable_dma(dma); clear_dma_ff(dma); info->stat_flags &= ~ESP_STAT_DMA_RX; - bytes_left = num_bytes = dma_bytes - get_dma_residue(dma); + num_bytes = dma_bytes - get_dma_residue(dma); info->icount.rx += num_bytes; - buffer = &(tty->flip); - - if (info->tty_buf->count && (tty->flip.count < TTY_FLIPBUF_SIZE)) - do_ttybuf(info); - - while (bytes_left > 0) { - if ((buffer->count + bytes_left) > TTY_FLIPBUF_SIZE) - x_bytes = TTY_FLIPBUF_SIZE - buffer->count; - else - x_bytes = bytes_left; - memcpy(buffer->char_buf_ptr, - dma_buffer + (num_bytes - bytes_left), x_bytes); - buffer->char_buf_ptr += x_bytes; - buffer->count += x_bytes; - memset(buffer->flag_buf_ptr, 0, x_bytes); - buffer->flag_buf_ptr += x_bytes; - bytes_left -= x_bytes; - - if (bytes_left > 0) { - if (buffer == info->tty_buf) - break; - else - buffer = info->tty_buf; - } - } + memcpy(tty->flip.char_buf_ptr, dma_buffer, num_bytes); + tty->flip.char_buf_ptr += num_bytes; + tty->flip.count += num_bytes; + memset(tty->flip.flag_buf_ptr, 0, num_bytes); + tty->flip.flag_buf_ptr += num_bytes; if (num_bytes > 0) { - buffer->flag_buf_ptr--; + tty->flip.flag_buf_ptr--; status &= (0x1c & info->read_status_mask); if (status & info->ignore_status_mask) { - buffer->count--; - buffer->char_buf_ptr--; - buffer->flag_buf_ptr--; + tty->flip.count--; + tty->flip.char_buf_ptr--; + tty->flip.flag_buf_ptr--; } else if (status & 0x10) { - *buffer->flag_buf_ptr = TTY_BREAK; + *tty->flip.flag_buf_ptr = TTY_BREAK; (info->icount.brk)++; if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (status & 0x08) { - *buffer->flag_buf_ptr = TTY_FRAME; + *tty->flip.flag_buf_ptr = TTY_FRAME; (info->icount.frame)++; } else if (status & 0x04) { - *buffer->flag_buf_ptr = TTY_PARITY; + *tty->flip.flag_buf_ptr = TTY_PARITY; (info->icount.parity)++; } - buffer->flag_buf_ptr++; + tty->flip.flag_buf_ptr++; - if (buffer == info->tty_buf) - queue_task(&info->tty_buf->tqueue, &tq_timer); - queue_task(&tty->flip.tqueue, &tq_timer); } if (dma_bytes != num_bytes) { + num_bytes = dma_bytes - num_bytes; dma_bytes = 0; - receive_chars_dma(info); + receive_chars_dma(info, num_bytes); } else dma_bytes = 0; } -static void transmit_chars_dma(struct esp_struct *info) +static _INLINE_ void transmit_chars_pio(struct esp_struct *info, + int space_avail) { - info->stat_flags &= ~ESP_STAT_NEED_DMA_TX; + int i; + struct esp_pio_buffer *pio_buf; - if ((info->xmit_cnt <= 0) || info->tty->stopped) { - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); - serial_out(info, UART_ESI_CMD2, info->IER); + pio_buf = get_pio_buffer(); + + if (!pio_buf) return; + + while (space_avail && info->xmit_cnt) { + if (info->xmit_tail + space_avail <= ESP_XMIT_SIZE) { + memcpy(pio_buf->data, + &(info->xmit_buf[info->xmit_tail]), + space_avail); + } else { + i = ESP_XMIT_SIZE - info->xmit_tail; + memcpy(pio_buf->data, + &(info->xmit_buf[info->xmit_tail]), i); + memcpy(&(pio_buf->data[i]), info->xmit_buf, + space_avail - i); + } + + info->xmit_cnt -= space_avail; + info->xmit_tail = (info->xmit_tail + space_avail) & + (ESP_XMIT_SIZE - 1); + + sti(); + + for (i = 0; i < space_avail - 1; i += 2) { + outw(*((unsigned short *)(pio_buf->data + i)), + info->port + UART_ESI_TX); + } + + if (space_avail & 0x0001) + serial_out(info, UART_ESI_TX, + pio_buf->data[space_avail - 1]); + + cli(); + + if (info->xmit_cnt) { + serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); + serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); + space_avail = serial_in(info, UART_ESI_STAT1) << 8; + space_avail |= serial_in(info, UART_ESI_STAT2); + + if (space_avail > info->xmit_cnt) + space_avail = info->xmit_cnt; + } } - - serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); - serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); - dma_bytes = serial_in(info, UART_ESI_STAT1) << 8; - dma_bytes |= serial_in(info, UART_ESI_STAT2); - if (!dma_bytes) - return; + if (info->xmit_cnt < WAKEUP_CHARS) { + rs_sched_event(info, ESP_EVENT_WRITE_WAKEUP); - if (dma_bytes > info->xmit_cnt) - dma_bytes = info->xmit_cnt; +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + + if (info->xmit_cnt <= 0) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_ESI_CMD1, + ESI_SET_SRV_MASK); + serial_out(info, UART_ESI_CMD2, info->IER); + } + } + + release_pio_buffer(pio_buf); +} + +static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes) +{ + dma_bytes = num_bytes; if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) { memcpy(dma_buffer, &(info->xmit_buf[info->xmit_tail]), @@ -507,9 +575,6 @@ { int num_bytes; - if (!(info->stat_flags & ESP_STAT_DMA_TX)) - return; - disable_dma(dma); clear_dma_ff(dma); @@ -564,8 +629,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif - queue_task(&info->tqueue_hangup, - &tq_scheduler); + queue_task(&info->tqueue_hangup, &tq_scheduler); } } } @@ -575,92 +639,104 @@ */ static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) { - struct esp_struct * info, *stop_port = 0; + struct esp_struct * info; unsigned err_status; unsigned int scratch; - int pre_bytes; - + #ifdef SERIAL_DEBUG_INTR printk("rs_interrupt_single(%d)...", irq); #endif - - /* This routine will currently check ALL ports when an interrupt */ - /* is received from ANY port */ + info = (struct esp_struct *)dev_id; + err_status = 0; + scratch = serial_in(info, UART_ESI_SID); - info = IRQ_ports[irq]; - - if (!info) + cli(); + + if (!info->tty) { + sti(); return; + } - do { - if (!info->tty) { - info = info->next_port; - continue; - } - - pre_bytes = dma_bytes; - err_status = 0; - scratch = serial_in(info, UART_ESI_SID); - if (scratch & 0x04) { /* error - check for rx timeout */ - serial_out(info, UART_ESI_CMD1, ESI_GET_ERR_STAT); - err_status = serial_in(info, UART_ESI_STAT1); - serial_in(info, UART_ESI_STAT2); + if (scratch & 0x04) { /* error */ + serial_out(info, UART_ESI_CMD1, ESI_GET_ERR_STAT); + err_status = serial_in(info, UART_ESI_STAT1); + serial_in(info, UART_ESI_STAT2); - if (err_status & 0x01) - info->stat_flags |= ESP_STAT_RX_TIMEOUT; + if (err_status & 0x01) + info->stat_flags |= ESP_STAT_RX_TIMEOUT; - if (err_status & 0x20) /* UART status */ - check_modem_status(info); + if (err_status & 0x20) /* UART status */ + check_modem_status(info); - if (err_status & 0x80) /* Start break */ - wake_up_interruptible(&info->break_wait); - } + if (err_status & 0x80) /* Start break */ + wake_up_interruptible(&info->break_wait); + } - if ((scratch & 0x88) || /* DMA completed or timed out */ - (err_status & 0x1c) /* receive error */) { - receive_chars_dma_done(info, err_status); - transmit_chars_dma_done(info); - } + if ((scratch & 0x88) || /* DMA completed or timed out */ + (err_status & 0x1c) /* receive error */) { + if (info->stat_flags & ESP_STAT_DMA_RX) + receive_chars_dma_done(info, err_status); + else if (info->stat_flags & ESP_STAT_DMA_TX) + transmit_chars_dma_done(info); + } - if (((scratch & 0x01) || - (info->stat_flags & ESP_STAT_RX_TIMEOUT)) && - (info->IER & UART_IER_RDI)) - if (dma_bytes) - info->stat_flags |= ESP_STAT_NEED_DMA_RX; - else - receive_chars_dma(info); + if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) && + ((scratch & 0x01) || (info->stat_flags & ESP_STAT_RX_TIMEOUT)) && + (info->IER & UART_IER_RDI)) { + int num_bytes; - if ((scratch & 0x02) && (info->IER & UART_IER_THRI)) - if (dma_bytes) - info->stat_flags |= ESP_STAT_NEED_DMA_TX; + serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); + serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL); + num_bytes = serial_in(info, UART_ESI_STAT1) << 8; + num_bytes |= serial_in(info, UART_ESI_STAT2); + + if (num_bytes > (TTY_FLIPBUF_SIZE - info->tty->flip.count)) + num_bytes = TTY_FLIPBUF_SIZE - info->tty->flip.count; + + if (num_bytes) { + if (dma_bytes || + (info->stat_flags & ESP_STAT_USE_PIO) || + (num_bytes <= ESP_PIO_THRESHOLD)) + receive_chars_pio(info, num_bytes); else - transmit_chars_dma(info); - - info->last_active = jiffies; - - if (pre_bytes && !dma_bytes) /* released DMA */ - stop_port = info; - - info = info->next_port; - } while ((info->irq == irq) && (info != IRQ_ports[irq])); + receive_chars_dma(info, num_bytes); + } + } + + if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) && + (scratch & 0x02) && (info->IER & UART_IER_THRI)) { + if ((info->xmit_cnt <= 0) || info->tty->stopped) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); + serial_out(info, UART_ESI_CMD2, info->IER); + } else { + int num_bytes; - if (stop_port) { - while ((info != stop_port) && (!dma_bytes)) { - if (info->tty) { - if (info->stat_flags & ESP_STAT_NEED_DMA_RX) - receive_chars_dma(info); - if ((info->stat_flags & ESP_STAT_NEED_DMA_TX) - && !dma_bytes) - transmit_chars_dma(info); + serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); + serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); + num_bytes = serial_in(info, UART_ESI_STAT1) << 8; + num_bytes |= serial_in(info, UART_ESI_STAT2); + + if (num_bytes > info->xmit_cnt) + num_bytes = info->xmit_cnt; + + if (num_bytes) { + if (dma_bytes || + (info->stat_flags & ESP_STAT_USE_PIO) || + (num_bytes <= ESP_PIO_THRESHOLD)) + transmit_chars_pio(info, num_bytes); + else + transmit_chars_dma(info, num_bytes); } - - info = info->next_port; } } + info->last_active = jiffies; + #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif + sti(); } /* @@ -734,7 +810,11 @@ { /* put ESPC in enhanced mode */ serial_out(info, UART_ESI_CMD1, ESI_SET_MODE); - serial_out(info, UART_ESI_CMD2, 0x31); + + if (info->stat_flags & ESP_STAT_NEVER_DMA) + serial_out(info, UART_ESI_CMD2, 0x01); + else + serial_out(info, UART_ESI_CMD2, 0x31); /* disable interrupts for now */ serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); @@ -742,8 +822,14 @@ /* set interrupt and DMA channel */ serial_out(info, UART_ESI_CMD1, ESI_SET_IRQ); - serial_out(info, UART_ESI_CMD2, (dma << 4) | 0x01); + + if (info->stat_flags & ESP_STAT_NEVER_DMA) + serial_out(info, UART_ESI_CMD2, 0x01); + else + serial_out(info, UART_ESI_CMD2, (dma << 4) | 0x01); + serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ); + if (info->line % 8) /* secondary port */ serial_out(info, UART_ESI_CMD2, 0x0d); /* shared */ else if (info->irq == 9) @@ -753,7 +839,12 @@ /* set error status mask (check this) */ serial_out(info, UART_ESI_CMD1, ESI_SET_ERR_MASK); - serial_out(info, UART_ESI_CMD2, 0xbd); + + if (info->stat_flags & ESP_STAT_NEVER_DMA) + serial_out(info, UART_ESI_CMD2, 0xa1); + else + serial_out(info, UART_ESI_CMD2, 0xbd); + serial_out(info, UART_ESI_CMD2, 0x00); /* set DMA timeout */ @@ -767,9 +858,9 @@ serial_out(info, UART_ESI_CMD2, tx_trigger >> 8); serial_out(info, UART_ESI_CMD2, tx_trigger); - /* Set clock scaling */ + /* Set clock scaling and wait states */ serial_out(info, UART_ESI_CMD1, ESI_SET_PRESCALAR); - serial_out(info, UART_ESI_CMD2, ESPC_SCALE); + serial_out(info, UART_ESI_CMD2, 0x04 | ESPC_SCALE); /* set reinterrupt pacing */ serial_out(info, UART_ESI_CMD1, ESI_SET_REINTR); @@ -780,43 +871,23 @@ { unsigned long flags; int retval=0; - int next_irq; - struct esp_struct *next_info = 0; unsigned int num_chars; save_flags(flags); cli(); - if (info->flags & ASYNC_INITIALIZED) - goto errout; + if (info->flags & ASYNC_INITIALIZED) { + restore_flags(flags); + return retval; + } if (!info->xmit_buf) { info->xmit_buf = (unsigned char *)get_free_page(GFP_KERNEL); if (!info->xmit_buf) { - retval = -ENOMEM; - goto errout; + restore_flags(flags); + return -ENOMEM; } } - if (!info->tty_buf) { - info->tty_buf = (struct tty_flip_buffer *)kmalloc( - sizeof(struct tty_flip_buffer), GFP_KERNEL); - - if (!info->tty_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; - retval = -ENOMEM; - goto errout; - } - - memset(info->tty_buf, 0, sizeof(struct tty_flip_buffer)); - info->tty_buf->tqueue.routine = do_ttybuf; - info->tty_buf->tqueue.data = info; - } - - info->tty_buf->count = 0; - info->tty_buf->char_buf_ptr = info->tty_buf->char_buf; - info->tty_buf->flag_buf_ptr = info->tty_buf->flag_buf; - #ifdef SERIAL_DEBUG_OPEN printk("starting up ttys%d (irq %d)...", info->line, info->irq); #endif @@ -841,44 +912,45 @@ serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); serial_out(info, UART_ESI_CMD2, rx_timeout); - info->stat_flags = 0; + /* clear all flags except the "never DMA" flag */ + info->stat_flags &= ESP_STAT_NEVER_DMA; + + if (info->stat_flags & ESP_STAT_NEVER_DMA) + info->stat_flags |= ESP_STAT_USE_PIO; /* - * Allocate the IRQ if necessary + * Allocate the IRQ */ - if (!IRQ_ports[info->irq]) { - retval = request_irq(info->irq, rs_interrupt_single, - SA_INTERRUPT, "esp serial", NULL); - - if (!retval) { - int i = 1; - - while ((i < 16) && !IRQ_ports[i]) - i++; - - if (i == 16) { - dma_buffer = (char *)__get_dma_pages(GFP_KERNEL, - __get_order(DMA_BUFFER_SZ)); - if (!dma_buffer) - retval = -ENOMEM; - else - retval = request_dma(dma, "esp serial"); + retval = request_irq(info->irq, rs_interrupt_single, SA_SHIRQ, + "esp serial", info); - if (retval) - free_irq(info->irq, NULL); - } + if (retval) { + if (suser()) { + if (info->tty) + set_bit(TTY_IO_ERROR, + &info->tty->flags); + retval = 0; } + + restore_flags(flags); + return retval; + } - if (retval) { - if (suser()) { - if (info->tty) - set_bit(TTY_IO_ERROR, - &info->tty->flags); - retval = 0; - } - goto errout; + if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) { + dma_buffer = (char *)__get_dma_pages( + GFP_KERNEL, __get_order(DMA_BUFFER_SZ)); + + /* use PIO mode if DMA buf/chan cannot be allocated */ + if (!dma_buffer) + info->stat_flags |= ESP_STAT_USE_PIO; + else if (request_dma(dma, "esp serial")) { + free_pages((unsigned int)dma_buffer, + __get_order(DMA_BUFFER_SZ)); + dma_buffer = 0; + info->stat_flags |= ESP_STAT_USE_PIO; } + } info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; @@ -899,38 +971,6 @@ clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - /* Remove port from "closed" chain */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[0] = info->next_port; - - /* - * Insert serial port into IRQ chain. - */ - next_irq = info->irq; - - do { - next_info = IRQ_ports[next_irq]; - - if (++next_irq > 15) - next_irq = 1; - } while (!next_info && (next_irq != info->irq)); - - if (!next_info) { - info->next_port = info; - info->prev_port = info; - } else { - info->next_port = next_info; - info->prev_port = next_info->prev_port; - next_info->prev_port->next_port = info; - next_info->prev_port = info; - } - - IRQ_ports[info->irq] = info; - /* * Set up the tty->alt_speed kludge */ @@ -953,10 +993,6 @@ info->flags |= ASYNC_INITIALIZED; restore_flags(flags); return 0; - -errout: - restore_flags(flags); - return retval; } /* @@ -984,67 +1020,36 @@ wake_up_interruptible(&info->delta_msr_wait); wake_up_interruptible(&info->break_wait); - /* stop a DMA transfer on the port being closed, and start the next - one */ + /* stop a DMA transfer on the port being closed */ if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) { - struct esp_struct *curr = info->next_port; - disable_dma(dma); clear_dma_ff(dma); dma_bytes = 0; - - while ((curr != info) && (!dma_bytes)) { - if (curr->tty) { - if (curr->stat_flags & ESP_STAT_NEED_DMA_RX) - receive_chars_dma(curr); - if ((curr->stat_flags & ESP_STAT_NEED_DMA_TX) - && !dma_bytes) - transmit_chars_dma(curr); - } - - curr = curr->next_port; - } } /* - * First unlink the serial port from the IRQ chain... + * Free the IRQ */ - info->next_port->prev_port = info->prev_port; - info->prev_port->next_port = info->next_port; + free_irq(info->irq, info); - if (IRQ_ports[info->irq] == info) { - if ((info->next_port == info) || - (info->next_port->irq != info->irq)) - IRQ_ports[info->irq] = 0; - else - IRQ_ports[info->irq] = info->next_port; - } + if (dma_buffer) { + struct esp_struct *current_port = ports; - /* Stick it on the "closed" chain */ - info->next_port = IRQ_ports[0]; - if (info->next_port) - info->next_port->prev_port = info; - info->prev_port = 0; - IRQ_ports[0] = info; - - /* - * Free the IRQ, if necessary - */ - if (!IRQ_ports[info->irq]) { - int i = 1; + while (current_port) { + if ((current_port != info) && + (current_port->flags & ASYNC_INITIALIZED)) + break; - while ((i < 16) && !IRQ_ports[i]) - i++; + current_port = current_port->next_port; + } - if (i == 16) { + if (!current_port) { free_dma(dma); - free_pages((unsigned int)dma_buffer, - __get_order(DMA_BUFFER_SZ)); + free_pages((unsigned int)dma_buffer, + __get_order(DMA_BUFFER_SZ)); dma_buffer = 0; - } - - free_irq(info->irq, NULL); + } } if (info->xmit_buf) { @@ -1052,25 +1057,6 @@ info->xmit_buf = 0; } - if (info->tty_buf) { - /* code borrowed from tty_io.c */ - if (info->tty_buf->tqueue.sync) { - struct tq_struct *tq, *prev; - - for (tq=tq_timer, prev=0; tq; prev=tq, tq=tq->next) { - if (tq == &info->tty_buf->tqueue) { - if (prev) - prev->next = tq->next; - else - tq_timer = tq->next; - break; - } - } - } - kfree(info->tty_buf); - info->tty_buf = 0; - } - info->IER = 0; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, 0x00); @@ -1398,7 +1384,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif @@ -1420,7 +1406,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + printk("unthrottle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif @@ -1477,9 +1463,9 @@ { struct serial_struct new_serial; struct esp_struct old_info; - unsigned int change_irq; + unsigned int change_irq; unsigned int change_flow; - int i, retval = 0; + int retval = 0; struct esp_struct *current_async; if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) @@ -1522,102 +1508,97 @@ info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); info->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if (new_serial.irq == 2) - new_serial.irq = 9; - - if (change_irq) { - i = 1; - - while ((i < 16) && !IRQ_ports[i]) - i++; + } else { + if (new_serial.irq == 2) + new_serial.irq = 9; - if (i < 16) { - current_async = IRQ_ports[i]; + if (change_irq) { + current_async = ports; - do { + while (current_async) { if ((current_async->line >= info->line) && (current_async->line < (info->line + 8))) { if (current_async == info) { if (current_async->count > 1) return -EBUSY; - } else + } else if (current_async->count) return -EBUSY; } current_async = current_async->next_port; - } while (current_async != IRQ_ports[i]); + } } - } - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - info->flags = ((info->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->custom_divisor = new_serial.custom_divisor; - info->close_delay = new_serial.close_delay * HZ/100; - info->closing_wait = new_serial.closing_wait * HZ/100; - flow_off = new_serial.reserved[2]; - flow_on = new_serial.reserved[3]; - - if ((new_serial.reserved[0] != rx_trigger) || - (new_serial.reserved[1] != tx_trigger)) { - unsigned long flags; - - rx_trigger = new_serial.reserved[0]; - tx_trigger = new_serial.reserved[1]; - save_flags(flags); cli(); - serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER); - serial_out(info, UART_ESI_CMD2, rx_trigger >> 8); - serial_out(info, UART_ESI_CMD2, rx_trigger); - serial_out(info, UART_ESI_CMD2, tx_trigger >> 8); - serial_out(info, UART_ESI_CMD2, tx_trigger); - restore_flags(flags); - } - if (((unsigned char)(new_serial.reserved_char[1]) != rx_timeout)) { - unsigned long flags; + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ - rx_timeout = (unsigned char)(new_serial.reserved_char[1]); - save_flags(flags); cli(); + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->custom_divisor = new_serial.custom_divisor; + info->close_delay = new_serial.close_delay * HZ/100; + info->closing_wait = new_serial.closing_wait * HZ/100; + flow_off = new_serial.reserved[2]; + flow_on = new_serial.reserved[3]; + + if ((new_serial.reserved[0] != rx_trigger) || + (new_serial.reserved[1] != tx_trigger)) { + unsigned long flags; + + rx_trigger = new_serial.reserved[0]; + tx_trigger = new_serial.reserved[1]; + save_flags(flags); cli(); + serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER); + serial_out(info, UART_ESI_CMD2, rx_trigger >> 8); + serial_out(info, UART_ESI_CMD2, rx_trigger); + serial_out(info, UART_ESI_CMD2, tx_trigger >> 8); + serial_out(info, UART_ESI_CMD2, tx_trigger); + restore_flags(flags); + } + + if (((unsigned char)(new_serial.reserved_char[1]) != + rx_timeout)) { + unsigned long flags; + + rx_timeout = (unsigned char) + (new_serial.reserved_char[1]); + save_flags(flags); cli(); + + if (info->IER & UART_IER_RDI) { + serial_out(info, UART_ESI_CMD1, + ESI_SET_RX_TIMEOUT); + serial_out(info, UART_ESI_CMD2, rx_timeout); + } - if (info->IER & UART_IER_RDI) { - serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); - serial_out(info, UART_ESI_CMD2, rx_timeout); + restore_flags(flags); } - restore_flags(flags); - } + if (change_irq) { + /* + * We need to shutdown the serial port at the old + * port/irq combination. + */ + shutdown(info); - if (change_irq) { - /* - * We need to shutdown the serial port at the old - * port/irq combination. - */ - shutdown(info); + current_async = ports; - current_async = IRQ_ports[0]; - while (current_async != 0) { - if ((current_async->line >= info->line) && - (current_async->line < (info->line + 8))) - current_async->irq = new_serial.irq; + while (current_async) { + if ((current_async->line >= info->line) && + (current_async->line < (info->line + 8))) + current_async->irq = new_serial.irq; - current_async = current_async->next_port; - } + current_async = current_async->next_port; + } - serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ); - if (info->irq == 9) - serial_out(info, UART_ESI_CMD2, 0x02); - else - serial_out(info, UART_ESI_CMD2, info->irq); + serial_out(info, UART_ESI_CMD1, ESI_SET_ENH_IRQ); + if (info->irq == 9) + serial_out(info, UART_ESI_CMD2, 0x02); + else + serial_out(info, UART_ESI_CMD2, info->irq); + } } - -check_and_exit: + if (info->flags & ASYNC_INITIALIZED) { if (((old_info.flags & ASYNC_SPD_MASK) != (info->flags & ASYNC_SPD_MASK)) || @@ -1635,6 +1616,7 @@ } } else retval = startup(info); + return retval; } @@ -2237,43 +2219,24 @@ static int esp_open(struct tty_struct *tty, struct file * filp) { struct esp_struct *info; - int i, retval, line; + int retval, line; unsigned long page; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; - /* check whether or not the port is on the closed chain */ + /* find the port in the chain */ - info = IRQ_ports[0]; + info = ports; while (info && (info->line != line)) info = info->next_port; - /* if the port is not on the closed chain, look for it on the */ - /* open chain */ - if (!info) { - i = 1; - - while ((i < 16) && !IRQ_ports[i]) - i++; - - if (i < 16) { - info = IRQ_ports[i]; - - do { - if (info->line == line) - break; - info = info->next_port; - } while (info != IRQ_ports[i]); - } - } - - if (!info || (info->line != line) || - serial_paranoia_check(info, tty->device, "esp_open")) + serial_paranoia_check(info, tty->device, "esp_open"); return -ENODEV; + } #ifdef SERIAL_DEBUG_OPEN printk("esp_open %s%d, count = %d\n", tty->driver.name, info->line, @@ -2379,8 +2342,7 @@ info->irq = 4; } - if (IRQ_ports[0] && - (IRQ_ports[0]->port == (info->port - 8))) { + if (ports && (ports->port == (info->port - 8))) { release_region(*region_start, info->port - *region_start); } else @@ -2414,14 +2376,11 @@ int i, offset; int region_start; struct esp_struct * info; + struct esp_struct *last_primary = 0; int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380}; init_bh(ESP_BH, do_serial_bh); - for (i = 0; i < 16; i++) { - IRQ_ports[i] = 0; - } - for (i = 0; i < NR_PRIMARY; i++) if (irq[i] != 0) if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) || @@ -2431,7 +2390,7 @@ irq[i] = 9; if ((dma != 1) && (dma != 3)) - dma = 1; + dma = 0; if ((rx_trigger < 1) || (rx_trigger > 1023)) rx_trigger = 768; @@ -2552,21 +2511,27 @@ info->tqueue_hangup.data = info; info->callout_termios = esp_callout_driver.init_termios; info->normal_termios = esp_driver.init_termios; - - if (IRQ_ports[0]) - IRQ_ports[0]->prev_port = info; - info->next_port = IRQ_ports[0]; - info->prev_port = 0; - IRQ_ports[0] = info; + info->next_port = ports; + ports = info; printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ", info->line, info->port, info->irq); - if (info->line % 8) + + if (info->line % 8) { printk("secondary port\n"); - else { + /* 8 port cards can't do DMA */ + info->stat_flags |= ESP_STAT_NEVER_DMA; + + if (last_primary) + last_primary->stat_flags |= ESP_STAT_NEVER_DMA; + } else { printk("primary port\n"); + last_primary = info; irq[i] = info->irq; } + if (!dma) + info->stat_flags |= ESP_STAT_NEVER_DMA; + info = (struct esp_struct *)kmalloc(sizeof(struct esp_struct), GFP_KERNEL); if (!info) @@ -2605,7 +2570,8 @@ unsigned long flags; int e1, e2; unsigned int region_start, region_end; - struct esp_struct *current_async, *temp_async; + struct esp_struct *temp_async; + struct esp_pio_buffer *pio_buf; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ save_flags(flags); @@ -2619,22 +2585,21 @@ e2); restore_flags(flags); - current_async = IRQ_ports[0]; - while (current_async != 0) { - if (current_async->port != 0) { - region_start = region_end = current_async->port; - temp_async = current_async; + while (ports) { + if (ports->port) { + region_start = region_end = ports->port; + temp_async = ports; - while (temp_async != 0) { + while (temp_async) { if ((region_start - temp_async->port) == 8) { region_start = temp_async->port; temp_async->port = 0; - temp_async = current_async; + temp_async = ports; } else if ((temp_async->port - region_end) == 8) { region_end = temp_async->port; temp_async->port = 0; - temp_async = current_async; + temp_async = ports; } else temp_async = temp_async->next_port; } @@ -2643,9 +2608,9 @@ region_end - region_start + 8); } - temp_async = current_async->next_port; - kfree(current_async); - current_async = temp_async; + temp_async = ports->next_port; + kfree(ports); + ports = temp_async; } if (dma_buffer) @@ -2654,5 +2619,11 @@ if (tmp_buf) free_page((unsigned long)tmp_buf); + + while (free_pio_buf) { + pio_buf = free_pio_buf->next; + kfree(free_pio_buf); + free_pio_buf = pio_buf; + } } #endif /* MODULE */ diff -ur --new-file old/linux/drivers/char/esp.h new/linux/drivers/char/esp.h --- old/linux/drivers/char/esp.h Tue Dec 31 20:30:29 1996 +++ new/linux/drivers/char/esp.h Fri Feb 13 00:47:44 1998 @@ -46,10 +46,13 @@ #define ESI_NO_COMMAND 0xff #define ESP_STAT_RX_TIMEOUT 0x01 -#define ESP_STAT_NEED_DMA_RX 0x02 -#define ESP_STAT_NEED_DMA_TX 0x04 -#define ESP_STAT_DMA_RX 0x08 -#define ESP_STAT_DMA_TX 0x10 +#define ESP_STAT_DMA_RX 0x02 +#define ESP_STAT_DMA_TX 0x04 +#define ESP_STAT_NEVER_DMA 0x08 +#define ESP_STAT_USE_PIO 0x10 + +/* Always use PIO for this number (or less) of bytes */ +#define ESP_PIO_THRESHOLD 32 #define ESP_EVENT_WRITE_WAKEUP 0 #define ESP_MAGIC 0x53ee @@ -82,7 +85,6 @@ int xmit_head; int xmit_tail; int xmit_cnt; - struct tty_flip_buffer *tty_buf; struct tq_struct tqueue; struct tq_struct tqueue_hangup; struct termios normal_termios; @@ -93,9 +95,13 @@ struct wait_queue *break_wait; struct async_icount icount; /* kernel counters for the 4 input interrupts */ struct esp_struct *next_port; /* For the linked list */ - struct esp_struct *prev_port; }; +struct esp_pio_buffer +{ + unsigned char data[1024]; + struct esp_pio_buffer *next; +}; #endif /* ESP_H */ diff -ur --new-file old/linux/drivers/char/fbmem.c new/linux/drivers/char/fbmem.c --- old/linux/drivers/char/fbmem.c Sat Sep 13 20:07:27 1997 +++ new/linux/drivers/char/fbmem.c Fri Feb 27 19:56:38 1998 @@ -220,7 +220,8 @@ if (remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; - vma->vm_dentry = dget(file->f_dentry); + vma->vm_file = file; + file->f_count++; return 0; } diff -ur --new-file old/linux/drivers/char/ftape/compressor/zftape-compress.c new/linux/drivers/char/ftape/compressor/zftape-compress.c --- old/linux/drivers/char/ftape/compressor/zftape-compress.c Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/compressor/zftape-compress.c Sat Feb 21 03:28:22 1998 @@ -31,7 +31,6 @@ char zftc_rev[] = "$Revision: 1.1.6.1 $"; char zftc_dat[] = "$Date: 1997/11/16 15:15:56 $"; -#include #include #include #include diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/fdc-io.c new/linux/drivers/char/ftape/lowlevel/fdc-io.c --- old/linux/drivers/char/ftape/lowlevel/fdc-io.c Tue Dec 2 18:33:16 1997 +++ new/linux/drivers/char/ftape/lowlevel/fdc-io.c Sat Feb 21 03:28:22 1998 @@ -26,6 +26,7 @@ * Linux. */ +#include /* for CONFIG_FT_* */ #include #include #include @@ -385,7 +386,7 @@ int fdc_interrupt_wait(unsigned int time) { struct wait_queue wait = {current, NULL}; - int current_blocked = current->blocked; + sigset_t old_sigmask; static int resetting = 0; TRACE_FUN(ft_t_fdc_dma); @@ -401,14 +402,23 @@ /* timeout time will be up to USPT microseconds too long ! */ current->timeout = jiffies + (1000 * time + FT_USPT - 1) / FT_USPT; current->state = TASK_INTERRUPTIBLE; - current->blocked = _BLOCK_ALL; /* isn't this already set by the - * high level routines? - */ + + spin_lock_irq(¤t->sigmask_lock); + old_sigmask = current->blocked; + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + add_wait_queue(&ftape_wait_intr, &wait); while (!ft_interrupt_seen && current->state != TASK_RUNNING) { schedule(); /* sets TASK_RUNNING on timeout */ } - current->blocked = current_blocked; /* restore */ + + spin_lock_irq(¤t->sigmask_lock); + current->blocked = old_sigmask; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + remove_wait_queue(&ftape_wait_intr, &wait); /* the following IS necessary. True: as well * wake_up_interruptible() as the schedule() set TASK_RUNNING diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-ctl.c new/linux/drivers/char/ftape/lowlevel/ftape-ctl.c --- old/linux/drivers/char/ftape/lowlevel/ftape-ctl.c Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/lowlevel/ftape-ctl.c Sat Jan 24 02:38:04 1998 @@ -794,8 +794,8 @@ i, *ft_buffer[i]->address); } } - if ((current->signal & _DONT_BLOCK) && - !(current->signal & _NEVER_BLOCK) && + if (sigtestsetmask(¤t->signal, _DONT_BLOCK) && + !(sigtestsetmask(¤t->signal, _NEVER_BLOCK)) && ftape_tape_running) { TRACE(ft_t_warn, "Interrupted by fatal signal and tape still running"); diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-init.h new/linux/drivers/char/ftape/lowlevel/ftape-init.h --- old/linux/drivers/char/ftape/lowlevel/ftape-init.h Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/lowlevel/ftape-init.h Sat Jan 24 02:38:04 1998 @@ -32,12 +32,9 @@ #include #include -#define _S(nr) (1<<((nr)-1)) -#define _NEVER_BLOCK (_S(SIGKILL)|_S(SIGSTOP)) -#define _DONT_BLOCK (_NEVER_BLOCK|_S(SIGINT)) -#define _DO_BLOCK (_S(SIGPIPE)) -#define _BLOCK_ALL (0xffffffffL) - +#define _NEVER_BLOCK (sigmask(SIGKILL) | sigmask(SIGSTOP)) +#define _DONT_BLOCK (_NEVER_BLOCK | sigmask(SIGINT)) +#define _DO_BLOCK (sigmask(SIGPIPE)) #ifndef QIC117_TAPE_MAJOR #define QIC117_TAPE_MAJOR 27 diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-rw.c new/linux/drivers/char/ftape/lowlevel/ftape-rw.c --- old/linux/drivers/char/ftape/lowlevel/ftape-rw.c Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/lowlevel/ftape-rw.c Sat Jan 24 02:38:04 1998 @@ -432,7 +432,8 @@ */ result = ftape_ready_wait(ftape_timeout.pause,&status); } - } while (ftape_tape_running && (current->signal & _NEVER_BLOCK) == 0); + } while (ftape_tape_running + && !(sigtestsetmask(¤t->signal, _NEVER_BLOCK))); #ifndef TESTING ft_location.known = 0; #endif @@ -660,7 +661,7 @@ * to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!! */ if (ftape_read_id() < 0 || !ft_location.known || - (current->signal & _DONT_BLOCK)) { + sigtestsetmask(¤t->signal, _DONT_BLOCK)) { ft_location.known = 0; if (!ftape_tape_running || ++failures > FT_SECTORS_PER_SEGMENT) { @@ -775,7 +776,7 @@ fast_seek(count, 1); logical_forward(); if (ftape_read_id() < 0 || !ft_location.known || - (current->signal & _DONT_BLOCK)) { + (sigtestsetmask(¤t->signal, _DONT_BLOCK))) { if ((!ftape_tape_running && !ft_location.known) || ++failures > FT_SECTORS_PER_SEGMENT) { TRACE_ABORT(-EIO, ft_t_err, @@ -1001,7 +1002,7 @@ while (result < 0 && retry++ <= 5 && !ft_failure && - (current->signal & _DONT_BLOCK) == 0) { + !(sigtestsetmask(¤t->signal, _DONT_BLOCK))) { if (retry && start_offset < 5) { start_offset ++; diff -ur --new-file old/linux/drivers/char/ftape/lowlevel/ftape-tracing.h new/linux/drivers/char/ftape/lowlevel/ftape-tracing.h --- old/linux/drivers/char/ftape/lowlevel/ftape-tracing.h Tue Nov 25 23:45:27 1997 +++ new/linux/drivers/char/ftape/lowlevel/ftape-tracing.h Sat Jan 24 02:38:04 1998 @@ -171,7 +171,7 @@ * but rather into ftape-rw.h (maybe) */ #define FT_SIGNAL_EXIT(sig_mask) \ - if (current->signal & (sig_mask)) { \ + if (sigtestsetmask(¤t->signal, sig_mask)) { \ TRACE_ABORT(-EINTR, \ ft_t_warn, \ "interrupted by non-blockable signal"); \ diff -ur --new-file old/linux/drivers/char/ftape/zftape/zftape-ctl.c new/linux/drivers/char/ftape/zftape/zftape-ctl.c --- old/linux/drivers/char/ftape/zftape/zftape-ctl.c Tue Nov 25 23:45:28 1997 +++ new/linux/drivers/char/ftape/zftape/zftape-ctl.c Tue Mar 10 23:43:13 1998 @@ -29,9 +29,6 @@ #include #define __NO_VERSION__ #include -#ifdef CONFIG_KERNELD -#include -#endif #include #include 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 Tue Nov 25 23:45:28 1997 +++ new/linux/drivers/char/ftape/zftape/zftape-init.c Tue Mar 10 23:43:13 1998 @@ -30,8 +30,8 @@ #include #include #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif #include #include @@ -73,7 +73,7 @@ /* Local vars. */ static int busy_flag = 0; -static int orig_sigmask; +static sigset_t orig_sigmask; /* the interface to the kernel vfs layer */ @@ -171,7 +171,7 @@ TRACE_ABORT(-ENXIO, ft_t_err, "failed: illegal unit nr"); } orig_sigmask = current->blocked; - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); result = _zft_open(MINOR(ino->i_rdev), filep->f_flags & O_ACCMODE); if (result < 0) { current->blocked = orig_sigmask; /* restore mask */ @@ -186,18 +186,15 @@ /* Mask signals that will disturb proper operation of the * program that is calling. */ - current->blocked = orig_sigmask | _DO_BLOCK; + current->blocked = orig_sigmask; + sigaddsetmask (¤t->blocked, _DO_BLOCK); TRACE_EXIT 0; } } /* Close floppy tape device */ -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,31) static int zft_close(struct inode *ino, struct file *filep) -#else -static void zft_close(struct inode *ino, struct file *filep) -#endif { int result; TRACE_FUN(ft_t_flow); @@ -210,7 +207,7 @@ TRACE_EXIT; /* keep busy_flag !(?) */ #endif } - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); result = _zft_close(); if (result < 0) { TRACE(ft_t_err, "_zft_close failed"); @@ -235,7 +232,7 @@ unsigned int command, unsigned long arg) { int result = -EIO; - int old_sigmask; + sigset_t old_sigmask; TRACE_FUN(ft_t_flow); if (!busy_flag || MINOR(ino->i_rdev) != zft_unit || ft_failure) { @@ -243,7 +240,7 @@ "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); /* This will work as long as sizeof(void *) == sizeof(long) */ result = _zft_ioctl(command, (void *) arg); current->blocked = old_sigmask; /* restore mask */ @@ -261,7 +258,7 @@ #endif { int result = -EIO; - int old_sigmask; + sigset_t old_sigmask; TRACE_FUN(ft_t_flow); if (!busy_flag || @@ -276,18 +273,14 @@ "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); if ((result = ftape_mmap(vma)) >= 0) { #ifndef MSYNC_BUG_WAS_FIXED static struct vm_operations_struct dummy = { NULL, }; vma->vm_ops = &dummy; #endif -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,45) - vma->vm_dentry = dget(filep->f_dentry); -#else - vma_set_inode (vma, ino); - inode_inc_count (ino); -#endif + vma->vm_file = filep; + filep->f_count++; } current->blocked = old_sigmask; /* restore mask */ TRACE_EXIT result; @@ -307,7 +300,7 @@ #endif { int result = -EIO; - int old_sigmask; + sigset_t old_sigmask; #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,60) struct inode *ino = fp->f_dentry->d_inode; #endif @@ -319,7 +312,7 @@ "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); result = _zft_read(buff, req_len); current->blocked = old_sigmask; /* restore mask */ TRACE(ft_t_data_flow, "return with count: %d", result); @@ -343,7 +336,7 @@ #endif { int result = -EIO; - int old_sigmask; + sigset_t old_sigmask; #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,60) struct inode *ino = fp->f_dentry->d_inode; #endif @@ -355,7 +348,7 @@ "failed: not busy, failure or wrong unit"); } old_sigmask = current->blocked; /* save mask */ - current->blocked = _BLOCK_ALL; + sigfillset(¤t->blocked); result = _zft_write(buff, req_len); current->blocked = old_sigmask; /* restore mask */ TRACE(ft_t_data_flow, "return with count: %d", result); @@ -398,7 +391,7 @@ int zft_cmpr_lock(int try_to_load) { if (zft_cmpr_ops == NULL) { -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (try_to_load) { request_module("zft-compressor"); if (zft_cmpr_ops == NULL) { diff -ur --new-file old/linux/drivers/char/ftape/zftape/zftape-read.c new/linux/drivers/char/ftape/zftape/zftape-read.c --- old/linux/drivers/char/ftape/zftape/zftape-read.c Tue Nov 25 23:45:28 1997 +++ new/linux/drivers/char/ftape/zftape/zftape-read.c Thu Mar 12 19:33:21 1998 @@ -24,12 +24,8 @@ * for the QIC-117 floppy-tape driver for Linux. */ -#include #include #include -#ifdef CONFIG_KERNELD -#include -#endif #include diff -ur --new-file old/linux/drivers/char/ftape/zftape/zftape-rw.c new/linux/drivers/char/ftape/zftape/zftape-rw.c --- old/linux/drivers/char/ftape/zftape/zftape-rw.c Tue Nov 25 23:45:28 1997 +++ new/linux/drivers/char/ftape/zftape/zftape-rw.c Sat Feb 21 03:28:22 1998 @@ -24,6 +24,7 @@ * zftape. */ +#include /* for CONFIG_ZFT_DFLT_BLK_SZ */ #include #include #include diff -ur --new-file old/linux/drivers/char/ftape/zftape/zftape-rw.h new/linux/drivers/char/ftape/zftape/zftape-rw.h --- old/linux/drivers/char/ftape/zftape/zftape-rw.h Tue Nov 25 23:45:28 1997 +++ new/linux/drivers/char/ftape/zftape/zftape-rw.h Sat Feb 21 03:28:22 1998 @@ -28,6 +28,7 @@ * */ +#include /* for CONFIG_ZFT_DFLT_BLK_SZ */ #include "../zftape/zftape-buffers.h" #define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape) diff -ur --new-file old/linux/drivers/char/ftape/zftape/zftape-write.c new/linux/drivers/char/ftape/zftape/zftape-write.c --- old/linux/drivers/char/ftape/zftape/zftape-write.c Tue Nov 25 23:45:28 1997 +++ new/linux/drivers/char/ftape/zftape/zftape-write.c Thu Mar 12 19:33:21 1998 @@ -24,12 +24,8 @@ * for the QIC-117 floppy-tape driver for Linux. */ -#include #include #include -#ifdef CONFIG_KERNELD -#include -#endif #include diff -ur --new-file old/linux/drivers/char/ftape/zftape/zftape_syms.c new/linux/drivers/char/ftape/zftape/zftape_syms.c --- old/linux/drivers/char/ftape/zftape/zftape_syms.c Tue Nov 25 23:45:28 1997 +++ new/linux/drivers/char/ftape/zftape/zftape_syms.c Sat Feb 21 03:28:22 1998 @@ -24,7 +24,6 @@ * the ftape floppy tape driver exports */ -#include #define __NO_VERSION__ #include diff -ur --new-file old/linux/drivers/char/hfmodem/Config.in new/linux/drivers/char/hfmodem/Config.in --- old/linux/drivers/char/hfmodem/Config.in Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/hfmodem/Config.in Tue Feb 3 00:18:15 1998 @@ -0,0 +1,6 @@ +comment 'Misc. hamradio protocols' +tristate 'Shortwave radio modem driver' CONFIG_HFMODEM +if [ "$CONFIG_HFMODEM" != "n" ]; then + bool ' HFmodem support for Soundblaster and compatible cards' CONFIG_HFMODEM_SBC + bool ' HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS +fi diff -ur --new-file old/linux/drivers/char/hfmodem/gentbl.c new/linux/drivers/char/hfmodem/gentbl.c --- old/linux/drivers/char/hfmodem/gentbl.c Tue Aug 5 18:48:55 1997 +++ new/linux/drivers/char/hfmodem/gentbl.c Thu Jan 22 00:34:19 1998 @@ -25,8 +25,8 @@ */ /*****************************************************************************/ - -#include + +/* This is compiled with HOSTCC - do not include any headers. */ #include #include diff -ur --new-file old/linux/drivers/char/hfmodem/main.c new/linux/drivers/char/hfmodem/main.c --- old/linux/drivers/char/hfmodem/main.c Sun Nov 30 19:30:19 1997 +++ new/linux/drivers/char/hfmodem/main.c Sat Feb 21 03:28:22 1998 @@ -31,6 +31,7 @@ /*****************************************************************************/ +#include /* for CONFIG_HFMODEM_WSS and CONFIG_HFMODEM_SBC */ #include #include diff -ur --new-file old/linux/drivers/char/hfmodem/modem.c new/linux/drivers/char/hfmodem/modem.c --- old/linux/drivers/char/hfmodem/modem.c Tue Aug 5 18:48:55 1997 +++ new/linux/drivers/char/hfmodem/modem.c Fri Feb 27 18:11:09 1998 @@ -561,6 +561,7 @@ unsigned long flags; int i, cnt1, cnt2; + poll_wait(file, &dev->wait, wait); save_flags(flags); cli(); for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) { @@ -576,7 +577,6 @@ cnt2++; } restore_flags(flags); - poll_wait(&dev->wait, wait); if (cnt1 || !cnt2) return POLLIN | POLLRDNORM; return 0; diff -ur --new-file old/linux/drivers/char/istallion.c new/linux/drivers/char/istallion.c --- old/linux/drivers/char/istallion.c Fri Dec 19 21:30:54 1997 +++ new/linux/drivers/char/istallion.c Tue Feb 10 01:12:55 1998 @@ -3,7 +3,7 @@ /* * istallion.c -- stallion intelligent multiport serial driver. * - * Copyright (C) 1996-1997 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1998 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 @@ -170,7 +170,7 @@ */ static char *stli_drvtitle = "Stallion Intelligent Multiport Serial Driver"; static char *stli_drvname = "istallion"; -static char *stli_drvversion = "5.4.1"; +static char *stli_drvversion = "5.4.3"; static char *stli_serialname = "ttyE"; static char *stli_calloutname = "cue"; @@ -498,8 +498,8 @@ /* * Define macros to extract a brd or port number from a minor number. */ -#define MKDEV2BRD(min) (((min) & 0xc0) >> 6) -#define MKDEV2PORT(min) ((min) & 0x3f) +#define MINOR2BRD(min) (((min) & 0xc0) >> 6) +#define MINOR2PORT(min) ((min) & 0x3f) /* * Define a baud rate table that converts termios baud rate selector @@ -749,12 +749,8 @@ } iounmap(brdp->membase); - if ((brdp->brdtype == BRD_ECP) || - (brdp->brdtype == BRD_ECPE) || - (brdp->brdtype == BRD_ECPMC)) - release_region(brdp->iobase, ECP_IOSIZE); - else - release_region(brdp->iobase, ONB_IOSIZE); + if (brdp->iosize > 0) + release_region(brdp->iobase, brdp->iosize); kfree_s(brdp, sizeof(stlibrd_t)); stli_brds[i] = (stlibrd_t *) NULL; } @@ -790,7 +786,7 @@ #endif minordev = MINOR(tty->device); - brdnr = MKDEV2BRD(minordev); + brdnr = MINOR2BRD(minordev); if (brdnr >= stli_nrbrds) return(-ENODEV); brdp = stli_brds[brdnr]; @@ -798,7 +794,7 @@ return(-ENODEV); if ((brdp->state & BST_STARTED) == 0) return(-ENODEV); - portnr = MKDEV2PORT(minordev); + portnr = MINOR2PORT(minordev); if ((portnr < 0) || (portnr > brdp->nrports)) return(-ENODEV); @@ -3688,7 +3684,8 @@ if ((brdp->iobase == 0) || (brdp->memaddr == 0)) return(-ENODEV); - if (check_region(brdp->iobase, ECP_IOSIZE)) + brdp->iosize = ECP_IOSIZE; + if (check_region(brdp->iobase, brdp->iosize)) printk("STALLION: Warning, unit %d I/O address %x conflicts " "with another device\n", brdp->brdnr, brdp->iobase); @@ -3797,7 +3794,7 @@ brdp->nrpanels++; } - request_region(brdp->iobase, ECP_IOSIZE, name); + request_region(brdp->iobase, brdp->iosize, name); brdp->state |= BST_FOUND; return(0); } @@ -3826,7 +3823,8 @@ if ((brdp->iobase == 0) || (brdp->memaddr == 0)) return(-ENODEV); - if (check_region(brdp->iobase, ONB_IOSIZE)) + brdp->iosize = ONB_IOSIZE; + if (check_region(brdp->iobase, brdp->iosize)) printk("STALLION: Warning, unit %d I/O address %x conflicts " "with another device\n", brdp->brdnr, brdp->iobase); @@ -3954,7 +3952,7 @@ } brdp->panels[0] = brdp->nrports; - request_region(brdp->iobase, ONB_IOSIZE, name); + request_region(brdp->iobase, brdp->iosize, name); brdp->state |= BST_FOUND; return(0); } diff -ur --new-file old/linux/drivers/char/joystick.c new/linux/drivers/char/joystick.c --- old/linux/drivers/char/joystick.c Mon Dec 1 20:05:41 1997 +++ new/linux/drivers/char/joystick.c Fri Feb 27 04:59:33 1998 @@ -10,7 +10,6 @@ * and credits. */ -#include #include #include #include @@ -595,7 +594,7 @@ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); curl = file->private_data; - poll_wait(&jsd[minor].wait, wait); + poll_wait(file, &jsd[minor].wait, wait); if (GOF(curl->tail) != jsd[minor].ahead) return POLLIN | POLLRDNORM; return 0; diff -ur --new-file old/linux/drivers/char/keyboard.c new/linux/drivers/char/keyboard.c --- old/linux/drivers/char/keyboard.c Thu Dec 4 00:21:57 1997 +++ new/linux/drivers/char/keyboard.c Mon Jan 26 20:43:18 1998 @@ -80,7 +80,6 @@ /* shift state counters.. */ static unsigned char k_down[NR_SHIFT] = {0, }; /* keyboard key bitmap */ -#define BITS_PER_LONG (8*sizeof(unsigned long)) static unsigned long key_down[256/BITS_PER_LONG] = { 0, }; static int dead_key_next = 0; @@ -603,7 +602,7 @@ static void do_pad(unsigned char value, char up_flag) { static const char *pad_chars = "0123456789+-*/\015,.?()"; - static const char *app_map = "pqrstuvwxylSRQMnn?PQ"; + static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; if (up_flag) return; /* no action, if this is a key release */ diff -ur --new-file old/linux/drivers/char/lp.c new/linux/drivers/char/lp.c --- old/linux/drivers/char/lp.c Sun Nov 30 23:00:38 1997 +++ new/linux/drivers/char/lp.c Thu Feb 26 21:42:38 1998 @@ -1,4 +1,6 @@ /* + * Generic parallel printer driver + * * Copyright (C) 1992 by Jim Weigand and Linus Torvalds * Copyright (C) 1992,1993 by Michael K. Johnson * - Thanks much to Gunter Windau for pointing out to me where the error @@ -11,14 +13,58 @@ * lp_read (Status readback) support added by Carsten Gross, * carsten@sol.wohnheim.uni-ulm.de * Support for parport by Philip Blundell - * Reverted interrupt to polling at runtime if more than one device is parport - * registered and joined the interrupt and polling code. - * by Andrea Arcangeli + * parport_sharing hacking by Andrea Arcangeli */ -/* This driver is about due for a rewrite. */ +/* This driver should, in theory, work with any parallel port that has an + * appropriate low-level driver; all I/O is done through the parport + * abstraction layer. There is a performance penalty for this, but parallel + * ports are comparitively low-speed devices anyway. + * + * If this driver is built into the kernel, you can configure it using the + * kernel command-line. For example: + * + * lp=parport1,none,parport2 (bind lp0 to parport1, disable lp1 and + * bind lp2 to parport2) + * + * lp=auto (assign lp devices to all ports that + * have printers attached, as determined + * by the IEEE-1284 autoprobe) + * + * lp=reset (reset the printer during + * initialisation) + * + * lp=off (disable the printer driver entirely) + * + * If the driver is loaded as a module, similar functionality is available + * using module parameters. The equivalent of the above commands would be: + * + * # insmod lp.o parport=1,-1,2 (use -1 for disabled ports, since + * module parameters do not allow you + * to mix textual and numeric values) + * + * # insmod lp.o autoprobe=1 + * + * # insmod lp.0 reset=1 + */ + +/* COMPATIBILITY WITH OLD KERNELS + * + * Under Linux 2.0 and previous versions, lp devices were bound to ports at + * particular I/O addresses, as follows: + * + * lp0 0x3bc + * lp1 0x378 + * lp2 0x278 + * + * The new driver, by default, binds lp devices to parport devices as it + * finds them. This means that if you only have one port, it will be bound + * to lp0 regardless of its I/O address. If you need the old behaviour, you + * can force it using the parameters described above. + */ #include +#include #include #include @@ -26,31 +72,24 @@ #include #include #include -#include #include #include +#include +#include + #include -#include #include #include -#include -#include /* if you have more than 3 printers, remember to increase LP_NO */ -struct lp_struct lp_table[] = -{ - {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0, - {0}}, - {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0, - {0}}, - {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0, - {0}} -}; #define LP_NO 3 -/* Device name */ -static char *dev_name = "lp"; +struct lp_struct lp_table[LP_NO] = +{ + [0 ... LP_NO-1] = {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, + NULL, 0, 0, 0, {0}} +}; /* Test if printer is ready (and optionally has no error conditions) */ #define LP_READY(minor, status) \ @@ -64,61 +103,60 @@ #undef LP_DEBUG #undef LP_READ_DEBUG -/* Magic numbers */ -#define AUTO -3 -#define OFF -2 -#define UNSPEC -1 +/* --- parport support ----------------------------------------- */ -static inline void lp_parport_release (int minor) +static int lp_preempt(void *handle) { - parport_release (lp_table[minor].dev); - lp_table[minor].should_relinquish = 0; -} + struct lp_struct *lps = (struct lp_struct *)handle; -static inline void lp_parport_claim (int minor) -{ - if (parport_claim (lp_table[minor].dev)) - sleep_on (&lp_table[minor].lp_wait_q); + if (waitqueue_active (&lps->dev->wait_q)) + wake_up_interruptible(&lps->dev->wait_q); + + /* Don't actually release the port now */ + return 1; } -static inline void lp_schedule (int minor) +#define lp_parport_release(x) do { parport_release(lp_table[(x)].dev); } while (0); +#define lp_parport_claim(x) do { parport_claim_or_block(lp_table[(x)].dev); } while (0); + +/* --- low-level port access ----------------------------------- */ + +#define r_dtr(x) (parport_read_data(lp_table[(x)].dev->port)) +#define r_str(x) (parport_read_status(lp_table[(x)].dev->port)) +#define w_ctr(x,y) do { parport_write_control(lp_table[(x)].dev->port, (y)); } while (0) +#define w_dtr(x,y) do { parport_write_data(lp_table[(x)].dev->port, (y)); } while (0) + +static __inline__ void lp_yield (int minor) { - if (lp_table[minor].should_relinquish) { - lp_parport_release (minor); - schedule (); - lp_parport_claim (minor); - } - else + if (!parport_yield_blocking (lp_table[minor].dev) && need_resched) schedule (); } - -static int lp_preempt (void *handle) +static __inline__ void lp_schedule(int minor) { - struct lp_struct *lps = (struct lp_struct *)handle; - - /* Just remember that someone wants the port */ - lps->should_relinquish = 1; - - /* Don't actually release the port now */ - return 1; + struct pardevice *dev = lp_table[minor].dev; + register unsigned long int timeslip = (jiffies - dev->time); + if ((timeslip > dev->timeslice) && (dev->port->waithead != NULL)) { + lp_parport_release(minor); + schedule (); + lp_parport_claim(minor); + } else + schedule(); } static int lp_reset(int minor) { + int retval; + lp_parport_claim (minor); w_ctr(minor, LP_PSELECP); - udelay(LP_DELAY); + udelay (LP_DELAY); w_ctr(minor, LP_PSELECP | LP_PINITP); - return r_str(minor); -} - -static inline int must_use_polling(int minor) -{ - return lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE || - lp_table[minor].dev->port->devices->next; + retval = r_str(minor); + lp_parport_release (minor); + return retval; } -static inline int lp_char(char lpchar, int minor, int use_polling) +static inline int lp_char(char lpchar, int minor) { int status; unsigned int wait = 0; @@ -126,28 +164,33 @@ struct lp_stats *stats; do { - status = r_str(minor); + status = r_str (minor); count++; - if (need_resched) - lp_schedule (minor); - } while (((use_polling && !LP_READY(minor, status)) || - (!use_polling && !(status & LP_PBUSY))) && - (count < LP_CHAR(minor))); + lp_yield(minor); + } while (!LP_READY(minor, status) && count < LP_CHAR(minor)); - if (count == LP_CHAR(minor) || - (!use_polling && !LP_CAREFUL_READY(minor, status))) + if (count == LP_CHAR(minor)) return 0; + w_dtr(minor, lpchar); stats = &LP_STAT(minor); stats->chars++; /* must wait before taking strobe high, and after taking strobe low, according spec. Some printers need it, others don't. */ +#ifndef __sparc__ while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */ wait++; +#else + udelay(1); +#endif /* control port takes strobe high */ w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE); +#ifndef __sparc__ while (wait) /* FIXME: should be a udelay() */ wait--; +#else + udelay(1); +#endif /* take strobe low */ w_ctr(minor, LP_PSELECP | LP_PINITP); /* update waittime statistics */ @@ -170,19 +213,42 @@ { struct lp_struct *lp_dev = (struct lp_struct *) dev_id; - if (waitqueue_active (&lp_dev->lp_wait_q)) - wake_up(&lp_dev->lp_wait_q); + if (waitqueue_active (&lp_dev->dev->wait_q)) + wake_up_interruptible(&lp_dev->dev->wait_q); } static void lp_error(int minor) { - if (must_use_polling(minor)) { + if (LP_POLLING(minor) || LP_PREEMPTED(minor)) { current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + LP_TIMEOUT_POLLED; - lp_schedule (minor); + lp_parport_release(minor); + schedule(); + lp_parport_claim(minor); } } +static int lp_check_status(int minor) { + unsigned char status = r_str(minor); + if ((status & LP_POUTPA)) { + printk(KERN_INFO "lp%d out of paper\n", minor); + if (LP_F(minor) & LP_ABORT) + return 1; + lp_error(minor); + } else if (!(status & LP_PSELECD)) { + printk(KERN_INFO "lp%d off-line\n", minor); + if (LP_F(minor) & LP_ABORT) + return 1; + lp_error(minor); + } else if (!(status & LP_PERRORP)) { + printk(KERN_ERR "lp%d printer error\n", minor); + if (LP_F(minor) & LP_ABORT) + return 1; + lp_error(minor); + } + return 0; +} + static inline int lp_write_buf(unsigned int minor, const char *buf, int count) { unsigned long copy_size; @@ -202,7 +268,7 @@ copy_from_user(lp->lp_buffer, buf, copy_size); while (copy_size) { - if (lp_char(lp->lp_buffer[bytes_written], minor, must_use_polling(minor))) { + if (lp_char(lp->lp_buffer[bytes_written], minor)) { --copy_size; ++bytes_written; lp_table[minor].runchars++; @@ -210,36 +276,24 @@ int rc = total_bytes_written + bytes_written; if (lp_table[minor].runchars > LP_STAT(minor).maxrun) LP_STAT(minor).maxrun = lp_table[minor].runchars; - status = r_str(minor); - if ((status & LP_POUTPA)) { - printk(KERN_INFO "lp%d out of paper\n", minor); - if (LP_F(minor) & LP_ABORT) - return rc ? rc : -ENOSPC; - lp_error(minor); - } else if (!(status & LP_PSELECD)) { - printk(KERN_INFO "lp%d off-line\n", minor); - if (LP_F(minor) & LP_ABORT) - return rc ? rc : -EIO; - lp_error(minor); - } else if (!(status & LP_PERRORP)) { - printk(KERN_ERR "lp%d printer error\n", minor); - if (LP_F(minor) & LP_ABORT) - return rc ? rc : -EIO; - lp_error(minor); - } - LP_STAT(minor).sleeps++; - if (must_use_polling(minor)) { + if (LP_POLLING(minor)) { + lp_polling: + if (lp_check_status(minor)) + return rc ? rc : -EIO; #ifdef LP_DEBUG printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp_table[minor].runchars, LP_TIME(minor)); #endif - lp_table[minor].runchars = 0; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + LP_TIME(minor); lp_schedule (minor); } else { cli(); + if (LP_PREEMPTED(minor)) { + sti(); + goto lp_polling; + } enable_irq(lp->dev->port->irq); w_ctr(minor, LP_PSELECP|LP_PINITP|LP_PINTEN); status = r_str(minor); @@ -249,14 +303,17 @@ sti(); continue; } - lp_table[minor].runchars = 0; current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; - interruptible_sleep_on(&lp->lp_wait_q); - + interruptible_sleep_on(&lp->dev->wait_q); + disable_irq(lp->dev->port->irq); w_ctr(minor, LP_PSELECP | LP_PINITP); sti(); + if (lp_check_status(minor)) + return rc ? rc : -EIO; } + lp_table[minor].runchars = 0; + if (signal_pending(current)) { if (total_bytes_written + bytes_written) return total_bytes_written + bytes_written; @@ -287,12 +344,11 @@ lp_table[minor].lastcall = jiffies; /* Claim Parport or sleep until it becomes available - * (see lp_wakeup() for details) */ lp_parport_claim (minor); retv = lp_write_buf(minor, buf, count); - + lp_parport_release (minor); return retv; } @@ -307,14 +363,15 @@ static int lp_read_nibble(int minor) { unsigned char i; - i=r_str(minor)>>3; - i&=~8; - if ( ( i & 0x10) == 0) i|=8; - return(i & 0x0f); + i = r_str(minor)>>3; + i &= ~8; + if ((i & 0x10) == 0) i |= 8; + return (i & 0x0f); } -static void lp_select_in_high(int minor) { - w_ctr(minor, (r_ctr(minor) | 8)); +static inline void lp_select_in_high(int minor) +{ + parport_frob_control(lp_table[minor].dev->port, 8, 8); } /* Status readback confirming to ieee1284 */ @@ -329,7 +386,6 @@ unsigned int minor=MINOR(file->f_dentry->d_inode->i_rdev); /* Claim Parport or sleep until it becomes available - * (see lp_wakeup() for details) */ lp_parport_claim (minor); @@ -351,26 +407,27 @@ return temp-buf; /* End of file */ } for (i=0; i<=(count*2); i++) { - w_ctr(minor, r_ctr(minor) | 2); /* AutoFeed high */ + parport_frob_control(lp_table[minor].dev->port, 2, 2); /* AutoFeed high */ do { - status=(r_str(minor) & 0x40); + status = (r_str(minor) & 0x40); udelay(50); counter++; if (need_resched) schedule (); - } while ( (status == 0x40) && (counter < 20) ); - if ( counter == 20 ) { /* Timeout */ + } while ((status == 0x40) && (counter < 20)); + if (counter == 20) { + /* Timeout */ #ifdef LP_READ_DEBUG printk(KERN_DEBUG "lp_read: (Autofeed high) timeout\n"); -#endif - w_ctr(minor, r_ctr(minor) & ~2); +#endif + parport_frob_control(lp_table[minor].dev->port, 2, 0); lp_select_in_high(minor); parport_release(lp_table[minor].dev); return temp-buf; /* end the read at timeout */ } counter=0; - z=lp_read_nibble(minor); - w_ctr(minor, r_ctr(minor) & ~2); /* AutoFeed low */ + z = lp_read_nibble(minor); + parport_frob_control(lp_table[minor].dev->port, 2, 0); /* AutoFeed low */ do { status=(r_str(minor) & 0x40); udelay(20); @@ -418,6 +475,7 @@ return -ENXIO; if (LP_F(minor) & LP_BUSY) return -EBUSY; + LP_F(minor) |= LP_BUSY; MOD_INC_USE_COUNT; @@ -427,27 +485,33 @@ a non-standard manner. This is strictly a Linux hack, and should most likely only ever be used by the tunelp application. */ if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) { - int status = r_str(minor); + int status; + lp_parport_claim (minor); + status = r_str(minor); + lp_parport_release (minor); if (status & LP_POUTPA) { printk(KERN_INFO "lp%d out of paper\n", minor); MOD_DEC_USE_COUNT; + LP_F(minor) &= ~LP_BUSY; return -ENOSPC; } else if (!(status & LP_PSELECD)) { printk(KERN_INFO "lp%d off-line\n", minor); MOD_DEC_USE_COUNT; + LP_F(minor) &= ~LP_BUSY; return -EIO; } else if (!(status & LP_PERRORP)) { printk(KERN_ERR "lp%d printer error\n", minor); MOD_DEC_USE_COUNT; + LP_F(minor) &= ~LP_BUSY; return -EIO; } } lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); if (!lp_table[minor].lp_buffer) { MOD_DEC_USE_COUNT; + LP_F(minor) &= ~LP_BUSY; return -ENOMEM; } - LP_F(minor) |= LP_BUSY; return 0; } @@ -462,7 +526,6 @@ return 0; } - static int lp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -520,7 +583,10 @@ if (retval) return retval; else { - int status = r_str(minor); + int status; + lp_parport_claim (minor); + status = r_str(minor); + lp_parport_release (minor); copy_to_user((int *) arg, &status, sizeof(int)); } break; @@ -571,20 +637,35 @@ lp_release }; -static int parport[LP_NO] = { UNSPEC, }; +/* --- initialisation code ------------------------------------- */ #ifdef MODULE -#define lp_init init_module + +static int parport[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; +static int reset = 0; +static int autoprobe = 0; + MODULE_PARM(parport, "1-" __MODULE_STRING(LP_NO) "i"); +MODULE_PARM(reset, "i"); +MODULE_PARM(autoprobe, "i"); #else +static int parport[LP_NO] __initdata = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC }; +static int reset __initdata = 0; + static int parport_ptr = 0; -void lp_setup(char *str, int *ints) +__initfunc(void lp_setup(char *str, int *ints)) { - /* Ugh. */ - if (!strncmp(str, "parport", 7)) { + if (!str) { + if (ints[0] == 0 || ints[1] == 0) { + /* disable driver on "lp=" or "lp=0" */ + parport[0] = LP_PARPORT_OFF; + } else { + printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]); + } + } else if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str+7, NULL, 10); if (parport_ptr < LP_NO) parport[parport_ptr++] = n; @@ -592,100 +673,104 @@ printk(KERN_INFO "lp: too many ports, %s ignored.\n", str); } else if (!strcmp(str, "auto")) { - parport[0] = AUTO; - } else { - if (ints[0] == 0 || ints[1] == 0) { - /* disable driver on "lp=" or "lp=0" */ - parport[0] = OFF; - } else { - printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]); - } + parport[0] = LP_PARPORT_AUTO; + } else if (!strcmp(str, "none")) { + parport[parport_ptr++] = LP_PARPORT_NONE; + } else if (!strcmp(str, "reset")) { + reset = 1; } } #endif -void lp_wakeup(void *ref) +int lp_register(int nr, struct parport *port) { - struct lp_struct *lp_dev = (struct lp_struct *) ref; - - if (!waitqueue_active (&lp_dev->lp_wait_q)) - return; /* Wake up whom? */ + lp_table[nr].dev = parport_register_device(port, "lp", + lp_preempt, NULL, + lp_interrupt, + PARPORT_DEV_TRAN, + (void *) &lp_table[nr]); + if (lp_table[nr].dev == NULL) + return 1; + lp_table[nr].flags |= LP_EXIST; - /* Claim the Parport */ - if (parport_claim(lp_dev->dev)) - return; /* Shouldn't happen */ + if (reset) + lp_reset(nr); - wake_up(&lp_dev->lp_wait_q); -} + printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, + (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); -static int inline lp_searchfor(int list[], int a) -{ - int i; - for (i = 0; i < LP_NO && list[i] != UNSPEC; i++) { - if (list[i] == a) return 1; - } return 0; } int lp_init(void) { - int count = 0; - struct parport *pb; - - if (parport[0] == OFF) return 0; - - pb = parport_enumerate(); - - while (pb) { - /* We only understand PC-style ports. */ - if (pb->modes & PARPORT_MODE_PCSPP) { - if (parport[0] == UNSPEC || - lp_searchfor(parport, count) || - (parport[0] == AUTO && - pb->probe_info.class == PARPORT_CLASS_PRINTER)) { - lp_table[count].dev = - parport_register_device(pb, dev_name, - lp_preempt, lp_wakeup, - lp_interrupt, PARPORT_DEV_TRAN, - (void *) &lp_table[count]); - lp_table[count].flags |= LP_EXIST; - init_waitqueue (&lp_table[count].lp_wait_q); - lp_parport_claim (count); - lp_reset (count); - lp_parport_release (count); - printk(KERN_INFO "lp%d: using %s (%s).\n", - count, pb->name, (pb->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); + unsigned int count = 0; + unsigned int i; + struct parport *port; + + switch (parport[0]) + { + case LP_PARPORT_OFF: + return 0; + + case LP_PARPORT_UNSPEC: + case LP_PARPORT_AUTO: + for (port = parport_enumerate(); port; port = port->next) { + + if (parport[0] == LP_PARPORT_AUTO && + port->probe_info.class != PARPORT_CLASS_PRINTER) + continue; + + if (!lp_register(count, port)) + if (++count == LP_NO) + break; + } + break; + + case LP_PARPORT_NONE: + default: + for (i = 0; i < LP_NO; i++) { + if (parport[i] >= 0) { + char buffer[16]; + sprintf(buffer, "parport%d", parport[i]); + for (port = parport_enumerate(); port; + port = port->next) { + if (!strcmp(port->name, buffer)) { + (void) lp_register(i, port); + count++; + break; + } + } } - if (++count == LP_NO) - break; } - pb = pb->next; - } + break; + } - /* Successful specified devices increase count - * Unsuccessful specified devices increase failed - */ - if (count) { + if (count) { if (register_chrdev(LP_MAJOR, "lp", &lp_fops)) { printk("lp: unable to get major %d\n", LP_MAJOR); return -EIO; } - return 0; + } else { + printk(KERN_INFO "lp: driver loaded but no devices found\n"); } - printk(KERN_INFO "lp: driver loaded but no devices found\n"); -#ifdef MODULE return 0; -#else - return 1; -#endif } #ifdef MODULE +int init_module(void) +{ + if (autoprobe) + parport[0] = LP_PARPORT_AUTO; + + return lp_init(); +} + void cleanup_module(void) { - int offset; + unsigned int offset; unregister_chrdev(LP_MAJOR, "lp"); for (offset = 0; offset < LP_NO; offset++) { diff -ur --new-file old/linux/drivers/char/lp_m68k.c new/linux/drivers/char/lp_m68k.c --- old/linux/drivers/char/lp_m68k.c Sat Sep 20 23:51:54 1997 +++ new/linux/drivers/char/lp_m68k.c Tue Mar 10 23:43:13 1998 @@ -43,8 +43,8 @@ #include #include #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif #ifdef CONFIG_AMIGA @@ -365,7 +365,7 @@ if (dev >= MAX_LP) return -ENODEV; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (!lp_table[dev]) { char modname[30]; diff -ur --new-file old/linux/drivers/char/mem.c new/linux/drivers/char/mem.c --- old/linux/drivers/char/mem.c Mon Dec 22 17:42:36 1997 +++ new/linux/drivers/char/mem.c Fri Feb 27 19:56:58 1998 @@ -30,10 +30,13 @@ void soundcard_init(void); #endif #ifdef CONFIG_ISDN -void isdn_init(void); +int isdn_init(void); #endif #ifdef CONFIG_PCWATCHDOG -void pcwatchdog_init(void); +int pcwatchdog_init(void); +#endif +#ifdef CONFIG_VIDEO_DEV +extern int videodev_init(void); #endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, @@ -139,7 +142,8 @@ if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start, vma->vm_page_prot)) return -EAGAIN; - vma->vm_dentry = dget(file->f_dentry); + vma->vm_file = file; + file->f_count++; return 0; } diff -ur --new-file old/linux/drivers/char/misc.c new/linux/drivers/char/misc.c --- old/linux/drivers/char/misc.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/char/misc.c Tue Mar 10 23:43:13 1998 @@ -26,6 +26,9 @@ * Idea by Jacques Gelinas , * adapted by Bjorn Ekwall * corrected by Alan Cox + * + * Changes for kmod (from kerneld): + Cyrus Durgin */ #include @@ -46,8 +49,8 @@ #include #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif /* @@ -78,6 +81,9 @@ extern int nvram_init(void); extern int radio_init(void); extern void hfmodem_init(void); +#ifdef CONFIG_PC110_PAD +extern int pc110pad_init(void); +#endif #ifdef CONFIG_PROC_FS static int misc_read_proc(char *buf, char **start, off_t offset, @@ -104,7 +110,7 @@ while ((c != &misc_list) && (c->minor != minor)) c = c->next; if (c == &misc_list) { -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD char modname[20]; sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor); request_module(modname); diff -ur --new-file old/linux/drivers/char/msbusmouse.c new/linux/drivers/char/msbusmouse.c --- old/linux/drivers/char/msbusmouse.c Thu Nov 13 16:29:28 1997 +++ new/linux/drivers/char/msbusmouse.c Fri Feb 27 04:59:43 1998 @@ -159,7 +159,7 @@ static unsigned int mouse_poll(struct file *file, poll_table * wait) { - poll_wait(&mouse.wait, wait); + poll_wait(file, &mouse.wait, wait); if (mouse.ready) return POLLIN | POLLRDNORM; return 0; 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 Sat Dec 6 20:26:26 1997 +++ new/linux/drivers/char/n_tty.c Thu Mar 12 02:37:13 1998 @@ -420,7 +420,7 @@ tty->num_overrun++; if (tty->overrun_time < (jiffies - HZ)) { - printk("%s: %d input overrun(s)\n", _tty_name(tty, buf), + printk("%s: %d input overrun(s)\n", tty_name(tty, buf), tty->num_overrun); tty->overrun_time = jiffies; tty->num_overrun = 0; @@ -656,6 +656,7 @@ const unsigned char *p; char *f, flags = TTY_NORMAL; int i; + char buf[64]; if (!tty->read_buf) return; @@ -693,8 +694,8 @@ n_tty_receive_overrun(tty); break; default: - printk("%s: unknown flag %d\n", tty_name(tty), - flags); + printk("%s: unknown flag %d\n", + tty_name(tty, buf), flags); break; } } @@ -1102,8 +1103,8 @@ { unsigned int mask = 0; - poll_wait(&tty->read_wait, wait); - poll_wait(&tty->write_wait, wait); + poll_wait(file, &tty->read_wait, wait); + poll_wait(file, &tty->write_wait, wait); if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty))) mask |= POLLIN | POLLRDNORM; if (tty->packet && tty->link->ctrl_status) diff -ur --new-file old/linux/drivers/char/pc110pad.c new/linux/drivers/char/pc110pad.c --- old/linux/drivers/char/pc110pad.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/char/pc110pad.c Fri Feb 27 04:59:56 1998 @@ -16,7 +16,6 @@ * 0.4 1997-11-09 Alan Cox - Single Unix VFS API changes */ -#include #include #include #include @@ -576,7 +575,7 @@ static unsigned int pad_poll(struct file *file, poll_table * wait) { - poll_wait(&queue, wait); + poll_wait(file, &queue, wait); if(button_pending || xy_pending) return POLLIN | POLLRDNORM; return 0; diff -ur --new-file old/linux/drivers/char/pms.c new/linux/drivers/char/pms.c --- old/linux/drivers/char/pms.c Sun Jan 4 19:40:15 1998 +++ new/linux/drivers/char/pms.c Sat Feb 21 03:28:22 1998 @@ -15,7 +15,6 @@ */ #include -#include #include #include #include @@ -610,7 +609,7 @@ { int y; int dw = 2*dev->width; - char *src = (char *)bus_to_virt((void *)mem_base); + char *src = (char *)bus_to_virt(mem_base); char tmp[dw+32]; /* using a temp buffer is faster than direct */ int cnt = 0; diff -ur --new-file old/linux/drivers/char/psaux.c new/linux/drivers/char/psaux.c --- old/linux/drivers/char/psaux.c Tue Jan 13 00:13:24 1998 +++ new/linux/drivers/char/psaux.c Fri Feb 27 04:54:02 1998 @@ -567,7 +567,7 @@ static unsigned int aux_poll(struct file *file, poll_table * wait) { - poll_wait(&queue->proc_list, wait); + poll_wait(file, &queue->proc_list, wait); if (aux_ready) return POLLIN | POLLRDNORM; return 0; diff -ur --new-file old/linux/drivers/char/pty.c new/linux/drivers/char/pty.c --- old/linux/drivers/char/pty.c Sat Jun 28 19:31:36 1997 +++ new/linux/drivers/char/pty.c Fri Feb 13 01:25:04 1998 @@ -2,6 +2,9 @@ * linux/drivers/char/pty.c * * Copyright (C) 1991, 1992 Linus Torvalds + * + * Added support for a Unix98-style ptmx device. + * -- C. Scott Ananian , 14-Jan-1998 */ #include @@ -191,6 +194,45 @@ return ((count < N_TTY_BUF_SIZE/2) ? 0 : count); } +/* + * Return the minor device number of a given pty. This lets us + * open a master pty with the multi-headed ptmx device, then + * find out which one we got after it is open, with an ioctl. + */ +static int pty_get_device_minor(struct tty_struct *tty, unsigned int *value) +{ + unsigned int result = MINOR(tty->device); + return put_user(result, value); +} +/* Set the lock flag on a pty */ +static int pty_set_lock(struct tty_struct *tty, int * arg) +{ + int val; + if (get_user(val,arg)) + return -EFAULT; + if (val) + set_bit(TTY_PTY_LOCK, &tty->flags); + else + clear_bit(TTY_PTY_LOCK, &tty->flags); + return 0; +} + +static int pty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + if (!tty) { + printk("pty_ioctl called with NULL tty!\n"); + return -EIO; + } + switch(cmd) { + case TIOCGPTN: /* Get PT Number */ + return pty_get_device_minor(tty, (unsigned int *)arg); + case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ + return pty_set_lock(tty, (int *) arg); + } + return -ENOIOCTLCMD; +} + static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; @@ -225,6 +267,8 @@ retval = -EIO; if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) goto out; + if (test_bit(TTY_PTY_LOCK, &tty->link->flags)) + goto out; if (tty->link->count != 1) goto out; @@ -304,6 +348,12 @@ old_pty_slave_driver.minor_start = 192; old_pty_slave_driver.num = (NR_PTYS > 64) ? 64 : NR_PTYS; old_pty_slave_driver.other = &old_pty_driver; + + /* only the master pty gets this ioctl (which is why we + * assign it here, instead of up with the rest of the + * pty_driver initialization. + */ + pty_driver.ioctl = pty_ioctl; if (tty_register_driver(&pty_driver)) panic("Couldn't register pty driver"); diff -ur --new-file old/linux/drivers/char/random.c new/linux/drivers/char/random.c --- old/linux/drivers/char/random.c Mon Dec 22 02:27:18 1997 +++ new/linux/drivers/char/random.c Fri Feb 27 05:00:12 1998 @@ -1140,8 +1140,8 @@ { unsigned int mask; - poll_wait(&random_read_wait, wait); - poll_wait(&random_write_wait, wait); + poll_wait(file, &random_read_wait, wait); + poll_wait(file, &random_write_wait, wait); mask = 0; if (random_state.entropy_count >= WAIT_INPUT_BITS) mask |= POLLIN | POLLRDNORM; diff -ur --new-file old/linux/drivers/char/riscom8.c new/linux/drivers/char/riscom8.c --- old/linux/drivers/char/riscom8.c Sat Sep 20 23:51:54 1997 +++ new/linux/drivers/char/riscom8.c Thu Mar 5 20:55:06 1998 @@ -1,7 +1,7 @@ /* * linux/drivers/char/riscom.c -- RISCom/8 multiport serial driver. * - * Copyright (C) 1994-1996 Dmitry Gorodchanin (begemot@bgm.rosprint.net) + * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com) * * This code is loosely based on the Linux serial driver, written by * Linus Torvalds, Theodore T'so and others. The RISCom/8 card diff -ur --new-file old/linux/drivers/char/riscom8.h new/linux/drivers/char/riscom8.h --- old/linux/drivers/char/riscom8.h Mon Sep 30 09:47:08 1996 +++ new/linux/drivers/char/riscom8.h Thu Mar 5 20:55:06 1998 @@ -1,7 +1,7 @@ /* * linux/drivers/char/riscom8.h -- RISCom/8 multiport serial driver. * - * Copyright (C) 1994-1996 Dmitry Gorodchanin (begemot@bgm.rosprint.net) + * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com) * * This code is loosely based on the Linux serial driver, written by * Linus Torvalds, Theodore T'so and others. The RISCom/8 card diff -ur --new-file old/linux/drivers/char/rocket.c new/linux/drivers/char/rocket.c --- old/linux/drivers/char/rocket.c Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/char/rocket.c Sat Feb 21 03:28:22 1998 @@ -55,12 +55,10 @@ #include #endif #include -#include #else /* !NEW_MODULES */ #ifdef MODVERSIONS #define MODULE #endif -#include #include #endif /* NEW_MODULES */ @@ -224,7 +222,7 @@ static void rp_start(struct tty_struct *tty); static inline int rocket_paranoia_check(struct r_port *info, - dev_t device, const char *routine) + kdev_t device, const char *routine) { #ifdef ROCKET_PARANOIA_CHECK static const char *badmagic = diff -ur --new-file old/linux/drivers/char/rtc.c new/linux/drivers/char/rtc.c --- old/linux/drivers/char/rtc.c Tue Dec 9 08:58:04 1997 +++ new/linux/drivers/char/rtc.c Sun Mar 15 19:25:42 1998 @@ -28,9 +28,14 @@ * Based on other minimal char device drivers, like Alan's * watchdog, Ted's random, etc. etc. * + * 1.07 Paul Gortmaker. + * 1.08 Miquel van Smoorenburg: disallow certain things on the + * DEC Alpha as the CMOS clock is also used for other things. + * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. + * */ -#define RTC_VERSION "1.07" +#define RTC_VERSION "1.09" #define RTC_IRQ 8 /* Can't see this changing soon. */ #define RTC_IO_EXTENT 0x10 /* Only really two ports, but... */ @@ -43,7 +48,6 @@ * this driver.) */ -#include #include #include #include @@ -58,13 +62,6 @@ #include #include -/* Adjust starting epoch if ARC console time is being used */ -#ifdef CONFIG_RTC_ARC -#define ARCFUDGE 20 -#else -#define ARCFUDGE 0 -#endif - /* * We sponge a minor off of the misc major. No need slurping * up another valuable major dev number for this. If you add @@ -82,7 +79,7 @@ size_t count, loff_t *ppos); static int rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); + unsigned int cmd, unsigned long arg); static unsigned int rtc_poll(struct file *file, poll_table *wait); @@ -106,8 +103,15 @@ unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ unsigned long rtc_irq_data = 0; /* our output to the world */ +/* + * If this driver ever becomes modularised, it will be really nice + * to make the epoch retain its value across module reload... + */ + +static unsigned long epoch = 1900; /* year corresponding to 0x00 */ + unsigned char days_in_mo[] = - {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* * A very tiny interrupt handler. It runs with SA_INTERRUPT set, @@ -175,7 +179,7 @@ retval = put_user(data, (unsigned long *)buf); if (!retval) retval = sizeof(unsigned long); -out: + out: current->state = TASK_RUNNING; remove_wait_queue(&rtc_wait, &wait); @@ -183,231 +187,257 @@ } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { unsigned long flags; struct rtc_time wtime; switch (cmd) { - case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ - { - mask_rtc_irq_bit(RTC_AIE); - return 0; - } - case RTC_AIE_ON: /* Allow alarm interrupts. */ - { - set_rtc_irq_bit(RTC_AIE); - return 0; - } - case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ - { - mask_rtc_irq_bit(RTC_PIE); - if (rtc_status & RTC_TIMER_ON) { - del_timer(&rtc_irq_timer); - rtc_status &= ~RTC_TIMER_ON; - } - return 0; + case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ + { + mask_rtc_irq_bit(RTC_AIE); + return 0; + } + case RTC_AIE_ON: /* Allow alarm interrupts. */ + { + set_rtc_irq_bit(RTC_AIE); + return 0; + } + case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ + { + mask_rtc_irq_bit(RTC_PIE); + if (rtc_status & RTC_TIMER_ON) { + del_timer(&rtc_irq_timer); + rtc_status &= ~RTC_TIMER_ON; } - case RTC_PIE_ON: /* Allow periodic ints */ - { + return 0; + } + case RTC_PIE_ON: /* Allow periodic ints */ + { - /* - * We don't really want Joe User enabling more - * than 64Hz of interrupts on a multi-user machine. - */ - if ((rtc_freq > 64) && (!suser())) - return -EACCES; - - if (!(rtc_status & RTC_TIMER_ON)) { - rtc_status |= RTC_TIMER_ON; - rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; - add_timer(&rtc_irq_timer); - } - set_rtc_irq_bit(RTC_PIE); - return 0; - } - case RTC_UIE_OFF: /* Mask ints from RTC updates. */ - { - mask_rtc_irq_bit(RTC_UIE); - return 0; + /* + * We don't really want Joe User enabling more + * than 64Hz of interrupts on a multi-user machine. + */ + if ((rtc_freq > 64) && (!suser())) + return -EACCES; + + if (!(rtc_status & RTC_TIMER_ON)) { + rtc_status |= RTC_TIMER_ON; + rtc_irq_timer.expires = jiffies + HZ/rtc_freq + 2*HZ/100; + add_timer(&rtc_irq_timer); } - case RTC_UIE_ON: /* Allow ints for RTC updates. */ - { - set_rtc_irq_bit(RTC_UIE); - return 0; - } - case RTC_ALM_READ: /* Read the present alarm time */ - { - /* - * This returns a struct rtc_time. Reading >= 0xc0 - * means "don't care" or "match all". Only the tm_hour, - * tm_min, and tm_sec values are filled in. - */ + set_rtc_irq_bit(RTC_PIE); + return 0; + } + case RTC_UIE_OFF: /* Mask ints from RTC updates. */ + { + mask_rtc_irq_bit(RTC_UIE); + return 0; + } + case RTC_UIE_ON: /* Allow ints for RTC updates. */ + { + set_rtc_irq_bit(RTC_UIE); + return 0; + } + case RTC_ALM_READ: /* Read the present alarm time */ + { + /* + * This returns a struct rtc_time. Reading >= 0xc0 + * means "don't care" or "match all". Only the tm_hour, + * tm_min, and tm_sec values are filled in. + */ - get_rtc_alm_time(&wtime); - break; - } - case RTC_ALM_SET: /* Store a time into the alarm */ - { - /* - * This expects a struct rtc_time. Writing 0xff means - * "don't care" or "match all". Only the tm_hour, - * tm_min and tm_sec are used. - */ - unsigned char hrs, min, sec; - struct rtc_time alm_tm; - - if (copy_from_user(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) - return -EFAULT; - - hrs = alm_tm.tm_hour; - min = alm_tm.tm_min; - sec = alm_tm.tm_sec; - - if (hrs >= 24) - hrs = 0xff; - - if (min >= 60) - min = 0xff; - - if (sec >= 60) - sec = 0xff; - - save_flags(flags); - cli(); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - } - CMOS_WRITE(hrs, RTC_HOURS_ALARM); - CMOS_WRITE(min, RTC_MINUTES_ALARM); - CMOS_WRITE(sec, RTC_SECONDS_ALARM); - restore_flags(flags); + get_rtc_alm_time(&wtime); + break; + } + case RTC_ALM_SET: /* Store a time into the alarm */ + { + /* + * This expects a struct rtc_time. Writing 0xff means + * "don't care" or "match all". Only the tm_hour, + * tm_min and tm_sec are used. + */ + unsigned char hrs, min, sec; + struct rtc_time alm_tm; + + if (copy_from_user(&alm_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + hrs = alm_tm.tm_hour; + min = alm_tm.tm_min; + sec = alm_tm.tm_sec; + + if (hrs >= 24) + hrs = 0xff; + + if (min >= 60) + min = 0xff; + + if (sec >= 60) + sec = 0xff; + + save_flags(flags); + cli(); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || + RTC_ALWAYS_BCD) + { + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + } + CMOS_WRITE(hrs, RTC_HOURS_ALARM); + CMOS_WRITE(min, RTC_MINUTES_ALARM); + CMOS_WRITE(sec, RTC_SECONDS_ALARM); + restore_flags(flags); - return 0; - } - case RTC_RD_TIME: /* Read the time/date from RTC */ - { - get_rtc_time(&wtime); - break; - } - case RTC_SET_TIME: /* Set the RTC */ - { - struct rtc_time rtc_tm; - unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control, save_freq_select; - unsigned int yrs; - unsigned long flags; + return 0; + } + case RTC_RD_TIME: /* Read the time/date from RTC */ + { + get_rtc_time(&wtime); + break; + } + case RTC_SET_TIME: /* Set the RTC */ + { + struct rtc_time rtc_tm; + unsigned char mon, day, hrs, min, sec, leap_yr; + unsigned char save_control, save_freq_select; + unsigned int yrs; + unsigned long flags; - if (!suser()) - return -EACCES; + if (!suser()) + return -EACCES; - if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) - return -EFAULT; + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, + sizeof(struct rtc_time))) + return -EFAULT; + + yrs = rtc_tm.tm_year + 1900; + mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm.tm_mday; + hrs = rtc_tm.tm_hour; + min = rtc_tm.tm_min; + sec = rtc_tm.tm_sec; - yrs = rtc_tm.tm_year + 1900 + ARCFUDGE; - mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ - day = rtc_tm.tm_mday; - hrs = rtc_tm.tm_hour; - min = rtc_tm.tm_min; - sec = rtc_tm.tm_sec; - - if ((yrs < 1970) || (yrs > 2069)) - return -EINVAL; + if (yrs < 1970) + return -EINVAL; - leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); + leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); - if ((mon > 12) || (day == 0)) - return -EINVAL; + if ((mon > 12) || (day == 0)) + return -EINVAL; - if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) - return -EINVAL; + if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) + return -EINVAL; - if ((hrs >= 24) || (min >= 60) || (sec >= 60)) - return -EINVAL; + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) + return -EINVAL; - if (yrs >= 2000) - yrs -= 2000; /* RTC (0, 1, ... 69) */ - else - yrs -= 1900; /* RTC (70, 71, ... 99) */ - - save_flags(flags); - cli(); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); + if ((yrs -= epoch) > 255) /* They are unsigned */ + return -EINVAL; + + save_flags(flags); + cli(); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) + || RTC_ALWAYS_BCD) { + if (yrs > 169) { + restore_flags(flags); + return -EINVAL; } + if (yrs >= 100) + yrs -= 100; - save_control = CMOS_READ(RTC_CONTROL); - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DAY_OF_MONTH); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); + BIN_TO_BCD(sec); + BIN_TO_BCD(min); + BIN_TO_BCD(hrs); + BIN_TO_BCD(day); + BIN_TO_BCD(mon); + BIN_TO_BCD(yrs); + } + + save_control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + CMOS_WRITE(yrs, RTC_YEAR); + CMOS_WRITE(mon, RTC_MONTH); + CMOS_WRITE(day, RTC_DAY_OF_MONTH); + CMOS_WRITE(hrs, RTC_HOURS); + CMOS_WRITE(min, RTC_MINUTES); + CMOS_WRITE(sec, RTC_SECONDS); - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - restore_flags(flags); - return 0; - } - case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ - { - return put_user(rtc_freq, (unsigned long *)arg); - } - case RTC_IRQP_SET: /* Set periodic IRQ rate. */ - { - int tmp = 0; - unsigned char val; + restore_flags(flags); + return 0; + } + case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ + { + return put_user(rtc_freq, (unsigned long *)arg); + } + case RTC_IRQP_SET: /* Set periodic IRQ rate. */ + { + int tmp = 0; + unsigned char val; - /* - * The max we can do is 8192Hz. - */ - if ((arg < 2) || (arg > 8192)) - return -EINVAL; - /* - * We don't really want Joe User generating more - * than 64Hz of interrupts on a multi-user machine. - */ - if ((arg > 64) && (!suser())) - return -EACCES; - - while (arg > (1< 8192)) + return -EINVAL; + /* + * We don't really want Joe User generating more + * than 64Hz of interrupts on a multi-user machine. + */ + if ((arg > 64) && (!suser())) + return -EACCES; + + while (arg > (1< 10 && year < 44) { + epoch = 1980; + guess = "ARC console"; + } else if (year < 96) { + epoch = 1952; + guess = "Digital UNIX"; + } + if (guess) + printk("rtc: %s epoch (%lu) detected\n", guess, epoch); +#endif init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; rtc_wait = NULL; @@ -572,10 +634,11 @@ * time or for Universal Standard Time (GMT). Probably local though. */ p += sprintf(p, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04lu\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); get_rtc_alm_time(&tm); @@ -601,24 +664,24 @@ p += sprintf(p, "**\n"); p += sprintf(p, - "DST_enable\t: %s\n" - "BCD\t\t: %s\n" - "24hr\t\t: %s\n" - "square_wave\t: %s\n" - "alarm_IRQ\t: %s\n" - "update_IRQ\t: %s\n" - "periodic_IRQ\t: %s\n" - "periodic_freq\t: %ld\n" - "batt_status\t: %s\n", - (ctrl & RTC_DST_EN) ? "yes" : "no", - (ctrl & RTC_DM_BINARY) ? "no" : "yes", - (ctrl & RTC_24H) ? "yes" : "no", - (ctrl & RTC_SQWE) ? "yes" : "no", - (ctrl & RTC_AIE) ? "yes" : "no", - (ctrl & RTC_UIE) ? "yes" : "no", - (ctrl & RTC_PIE) ? "yes" : "no", - rtc_freq, - batt ? "okay" : "dead"); + "DST_enable\t: %s\n" + "BCD\t\t: %s\n" + "24hr\t\t: %s\n" + "square_wave\t: %s\n" + "alarm_IRQ\t: %s\n" + "update_IRQ\t: %s\n" + "periodic_IRQ\t: %s\n" + "periodic_freq\t: %ld\n" + "batt_status\t: %s\n", + (ctrl & RTC_DST_EN) ? "yes" : "no", + (ctrl & RTC_DM_BINARY) ? "no" : "yes", + (ctrl & RTC_24H) ? "yes" : "no", + (ctrl & RTC_SQWE) ? "yes" : "no", + (ctrl & RTC_AIE) ? "yes" : "no", + (ctrl & RTC_UIE) ? "yes" : "no", + (ctrl & RTC_PIE) ? "yes" : "no", + rtc_freq, + batt ? "okay" : "dead"); return p - buf; } @@ -689,12 +752,9 @@ * Account for differences between how the RTC uses the values * and how they are defined in a struct rtc_time; */ - if (rtc_tm->tm_year <= 69) + if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) rtc_tm->tm_year += 100; - /* if ARCFUDGE == 0, the optimizer should do away with this */ - rtc_tm->tm_year -= ARCFUDGE; - rtc_tm->tm_mon--; } @@ -732,6 +792,7 @@ * We also clear out any old irq data after an ioctl() that * meddles with the interrupt enable/disable bits. */ + void mask_rtc_irq_bit(unsigned char bit) { unsigned char val; @@ -761,4 +822,3 @@ rtc_irq_data = 0; restore_flags(flags); } - diff -ur --new-file old/linux/drivers/char/selection.c new/linux/drivers/char/selection.c --- old/linux/drivers/char/selection.c Tue Jun 17 01:35:55 1997 +++ new/linux/drivers/char/selection.c Sat Feb 21 03:28:22 1998 @@ -11,7 +11,6 @@ * Now that /dev/vcs exists, most of this can disappear again. */ -#include #include #include #include diff -ur --new-file old/linux/drivers/char/serial.c new/linux/drivers/char/serial.c --- old/linux/drivers/char/serial.c Sun Dec 7 21:06:56 1997 +++ new/linux/drivers/char/serial.c Thu Mar 12 02:37:13 1998 @@ -1652,7 +1652,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif @@ -1676,7 +1676,7 @@ #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + printk("unthrottle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif diff -ur --new-file old/linux/drivers/char/specialix.c new/linux/drivers/char/specialix.c --- old/linux/drivers/char/specialix.c Thu Dec 4 02:36:26 1997 +++ new/linux/drivers/char/specialix.c Thu Mar 5 20:55:06 1998 @@ -2,7 +2,7 @@ * specialix.c -- specialix IO8+ multiport serial driver. * * Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl) - * Copyright (C) 1994-1996 Dmitry Gorodchanin (begemot@bgm.rosprint.net) + * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com) * * Specialix pays for the development and support of this driver. * Please DO contact io8-linux@specialix.co.uk if you require diff -ur --new-file old/linux/drivers/char/specialix_io8.h new/linux/drivers/char/specialix_io8.h --- old/linux/drivers/char/specialix_io8.h Tue Dec 2 18:19:03 1997 +++ new/linux/drivers/char/specialix_io8.h Thu Mar 5 20:55:06 1998 @@ -3,7 +3,7 @@ * Specialix IO8+ multiport serial driver. * * Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl) - * Copyright (C) 1994-1996 Dmitry Gorodchanin (begemot@bgm.rosprint.net) + * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com) * * * Specialix pays for the development and support of this driver. diff -ur --new-file old/linux/drivers/char/stallion.c new/linux/drivers/char/stallion.c --- old/linux/drivers/char/stallion.c Fri Dec 19 21:30:54 1997 +++ new/linux/drivers/char/stallion.c Tue Feb 10 01:12:55 1998 @@ -3,7 +3,7 @@ /* * stallion.c -- stallion multiport serial driver. * - * Copyright (C) 1996-1997 Stallion Technologies (support@stallion.oz.au). + * Copyright (C) 1996-1998 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 @@ -143,7 +143,7 @@ */ static char *stl_drvtitle = "Stallion Multiport Serial Driver"; static char *stl_drvname = "stallion"; -static char *stl_drvversion = "5.4.1"; +static char *stl_drvversion = "5.4.3"; static char *stl_serialname = "ttyE"; static char *stl_calloutname = "cue"; @@ -338,6 +338,8 @@ /*****************************************************************************/ +#ifdef CONFIG_PCI + /* * Define the Stallion PCI vendor and device IDs. */ @@ -372,13 +374,15 @@ static int stl_nrpcibrds = sizeof(stl_pcibrds) / sizeof(stlpcibrd_t); +#endif + /*****************************************************************************/ /* * Define macros to extract a brd/port number from a minor number. */ -#define MKDEV2BRD(min) (((min) & 0xc0) >> 6) -#define MKDEV2PORT(min) ((min) & 0x3f) +#define MINOR2BRD(min) (((min) & 0xc0) >> 6) +#define MINOR2PORT(min) ((min) & 0x3f) /* * Define a baud rate table that converts termios baud rate selector @@ -796,13 +800,13 @@ #endif minordev = MINOR(tty->device); - brdnr = MKDEV2BRD(minordev); + brdnr = MINOR2BRD(minordev); if (brdnr >= stl_nrbrds) return(-ENODEV); brdp = stl_brds[brdnr]; if (brdp == (stlbrd_t *) NULL) return(-ENODEV); - minordev = MKDEV2PORT(minordev); + minordev = MINOR2PORT(minordev); for (portnr = -1, panelnr = 0; (panelnr < STL_MAXPANELS); panelnr++) { if (brdp->panels[panelnr] == (stlpanel_t *) NULL) break; diff -ur --new-file old/linux/drivers/char/sysrq.c new/linux/drivers/char/sysrq.c --- old/linux/drivers/char/sysrq.c Mon Dec 22 02:27:17 1997 +++ new/linux/drivers/char/sysrq.c Tue Feb 10 01:12:55 1998 @@ -171,9 +171,9 @@ static void go_sync(kdev_t dev, int remount_flag) { - printk(KERN_INFO "%sing device %04x ... ", + printk(KERN_INFO "%sing device %s ... ", remount_flag ? "Remount" : "Sync", - dev); + kdevname(dev)); if (remount_flag) { /* Remount R/O */ struct super_block *sb = get_super(dev); diff -ur --new-file old/linux/drivers/char/tpqic02.c new/linux/drivers/char/tpqic02.c --- old/linux/drivers/char/tpqic02.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/char/tpqic02.c Sat Jan 24 02:38:04 1998 @@ -1766,8 +1766,10 @@ if (TP_DIAGS(current_tape_dev)) /* can't print a ``long long'' (for filp->f_pos), so chop it */ - printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n", - MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags); + printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx" + ", pos=%lx, flags=%x\n", + MINOR(dev), buf, (long) count, + (unsigned long) filp->f_pos, flags); if (count % TAPE_BLKSIZE) /* Only allow mod 512 bytes at a time. */ { @@ -1980,8 +1982,10 @@ if (TP_DIAGS(current_tape_dev)) { /* can't print a ``long long'' (for filp->f_pos), so chop it */ - printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%lx, pos=%lx, flags=%x\n", - MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags); + printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p" + ", count=%lx, pos=%lx, flags=%x\n", + MINOR(dev), buf, + (long) count, (unsigned long) filp->f_pos, flags); } if (count % TAPE_BLKSIZE) /* only allow mod 512 bytes at a time */ @@ -2128,7 +2132,9 @@ tpqputs(TPQD_ALWAYS, "write request for <0 bytes"); if (TPQDBG(DEBUG)) { - printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p, total_bytes_done %lx, count %lx\n", status_bytes_wr, buf, total_bytes_done, count); + printk(TPQIC02_NAME ": status_bytes_wr %x, buf %p" + ", total_bytes_done %lx, count %lx\n", + status_bytes_wr, buf, total_bytes_done, (long) count); } return -EINVAL; } /* qic02_tape_write */ @@ -2865,7 +2871,7 @@ return 0; } /* qic02_get_resources */ -__initfunc(static int qic02_tape_init(void)) +__initfunc(int qic02_tape_init(void)) { if (TPSTATSIZE != 6) { 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 Thu Jan 1 01:40:08 1998 +++ new/linux/drivers/char/tty_io.c Thu Mar 12 02:37:13 1998 @@ -51,6 +51,9 @@ * * Rewrote init_dev and release_dev to eliminate races. * -- Bill Hawes , June 97 + * + * Added support for a Unix98-style ptmx device. + * -- C. Scott Ananian , 14-Jan-1998 */ #include @@ -84,13 +87,14 @@ #include #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) #define TTY_DEV MKDEV(TTYAUX_MAJOR,0) #define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1) +#define PTMX_DEV MKDEV(TTYAUX_MAJOR,2) #undef TTY_DEBUG_HANGUP @@ -123,11 +127,9 @@ #endif /* - * These two routines return the name of tty. tty_name() should NOT - * be used in interrupt drivers, since it's not re-entrant. Use - * _tty_name() instead. + * This routine returns the name of tty. */ -char *_tty_name(struct tty_struct *tty, char *buf) +char *tty_name(struct tty_struct *tty, char *buf) { if (tty) sprintf(buf, "%s%d", tty->driver.name, @@ -138,13 +140,6 @@ return buf; } -char *tty_name(struct tty_struct *tty) -{ - static char buf[64]; - - return(_tty_name(tty, buf)); -} - inline int tty_paranoia_check(struct tty_struct *tty, kdev_t device, const char *routine) { @@ -209,11 +204,13 @@ { int retval = 0; struct tty_ldisc o_ldisc; + char buf[64]; if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) return -EINVAL; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD /* Eduardo Blanco */ + /* Cyrus Durgin */ if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) { char modname [20]; sprintf(modname, "tty-ldisc-%d", ldisc); @@ -250,7 +247,7 @@ if (r < 0) panic("Couldn't open N_TTY ldisc for " "%s --- error %d.", - tty_name(tty), r); + tty_name(tty, buf), r); } } } @@ -451,7 +448,9 @@ void tty_hangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP - printk("%s hangup...\n", tty_name(tty)); + char buf[64]; + + printk("%s hangup...\n", tty_name(tty, buf)); #endif queue_task(&tty->tq_hangup, &tq_timer); } @@ -459,7 +458,9 @@ void tty_vhangup(struct tty_struct * tty) { #ifdef TTY_DEBUG_HANGUP - printk("%s vhangup...\n", tty_name(tty)); + char buf[64]; + + printk("%s vhangup...\n", tty_name(tty, buf)); #endif do_tty_hangup((void *) tty); } @@ -946,6 +947,7 @@ struct tty_struct *tty, *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; int idx; + char buf[64]; tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev")) @@ -986,7 +988,7 @@ #endif #ifdef TTY_DEBUG_HANGUP - printk("release_dev of %s (tty count=%d)...", tty_name(tty), + printk("release_dev of %s (tty count=%d)...", tty_name(tty, buf), tty->count); #endif @@ -1064,7 +1066,7 @@ break; printk("release_dev: %s: read/write wait queue active!\n", - tty_name(tty)); + tty_name(tty, buf)); schedule(); } @@ -1080,13 +1082,13 @@ if (pty_master) { if (--o_tty->count < 0) { printk("release_dev: bad pty slave count (%d) for %s\n", - o_tty->count, tty_name(o_tty)); + o_tty->count, tty_name(o_tty, buf)); o_tty->count = 0; } } if (--tty->count < 0) { printk("release_dev: bad tty->count (%d) for %s\n", - tty->count, tty_name(tty)); + tty->count, tty_name(tty, buf)); tty->count = 0; } @@ -1171,10 +1173,10 @@ static int tty_open(struct inode * inode, struct file * filp) { struct tty_struct *tty; - int minor; int noctty, retval; kdev_t device; unsigned short saved_flags; + char buf[64]; saved_flags = filp->f_flags; retry_open: @@ -1203,19 +1205,46 @@ device = c->device(c); noctty = 1; } - minor = MINOR(device); - + if (device == PTMX_DEV) { + /* find a free pty. */ + struct tty_driver *driver = tty_drivers; + int minor; + + /* find the pty driver */ + for (driver=tty_drivers; driver; driver=driver->next) + if (driver->major == PTY_MASTER_MAJOR) + break; + if (!driver) return -ENODEV; + + /* find a minor device that is not in use. */ + for (minor=driver->minor_start; + minorminor_start+driver->num; + minor++) { + device = MKDEV(driver->major, minor); + retval = init_dev(device, &tty); + if (retval==0) break; /* success! */ + } + if (minor==driver->minor_start+driver->num) /* no success */ + return -EIO; /* no free ptys */ + + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ + noctty = 1; + goto init_dev_done; + } + retval = init_dev(device, &tty); if (retval) return retval; + /* N.B. this error exit may leave filp->f_flags with O_NONBLOCK set */ +init_dev_done: filp->private_data = tty; check_tty_count(tty, "tty_open"); if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_MASTER) noctty = 1; #ifdef TTY_DEBUG_HANGUP - printk("opening %s...", tty_name(tty)); + printk("opening %s...", tty_name(tty, buf)); #endif if (tty->driver.open) retval = tty->driver.open(tty, filp); @@ -1228,7 +1257,8 @@ if (retval) { #ifdef TTY_DEBUG_HANGUP - printk("error %d in opening %s...", retval, tty_name(tty)); + printk("error %d in opening %s...", retval, + tty_name(tty, buf)); #endif release_dev(filp); @@ -1252,6 +1282,11 @@ tty->session = current->session; tty->pgrp = current->pgrp; } + if ((tty->driver.type == TTY_DRIVER_TYPE_SERIAL) && + (tty->driver.subtype == SERIAL_TYPE_CALLOUT)) { + printk("Warning, %s opened, is a deprecated tty " + "callout device\n", tty_name(tty, buf)); + } return 0; } @@ -1931,8 +1966,10 @@ return kmem_start; } -static struct tty_driver dev_tty_driver, dev_console_driver, - dev_syscons_driver; +static struct tty_driver dev_tty_driver, dev_syscons_driver, dev_ptmx_driver; +#ifdef CONFIG_VT +static struct tty_driver dev_console_driver; +#endif /* * Ok, now we can initialize the rest of the tty devices and can count @@ -1973,6 +2010,17 @@ if (tty_register_driver(&dev_syscons_driver)) panic("Couldn't register /dev/console driver\n"); + + dev_ptmx_driver = dev_tty_driver; + dev_ptmx_driver.driver_name = "/dev/ptmx"; + dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5; + dev_ptmx_driver.major= MAJOR(PTMX_DEV); + dev_ptmx_driver.minor_start = MINOR(PTMX_DEV); + dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM; + dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX; + + if (tty_register_driver(&dev_ptmx_driver)) + panic("Couldn't register /dev/ptmx driver\n"); #ifdef CONFIG_VT dev_console_driver = dev_tty_driver; diff -ur --new-file old/linux/drivers/char/tty_ioctl.c new/linux/drivers/char/tty_ioctl.c --- old/linux/drivers/char/tty_ioctl.c Mon Nov 24 17:45:44 1997 +++ new/linux/drivers/char/tty_ioctl.c Thu Mar 12 02:37:13 1998 @@ -45,7 +45,9 @@ struct wait_queue wait = { current, NULL }; #ifdef TTY_DEBUG_WAIT_UNTIL_SENT - printk("%s wait until sent...\n", tty_name(tty)); + char buf[64]; + + printk("%s wait until sent...\n", tty_name(tty, buf)); #endif if (!tty->driver.chars_in_buffer) return; @@ -57,7 +59,8 @@ current->timeout = (unsigned) -1; do { #ifdef TTY_DEBUG_WAIT_UNTIL_SENT - printk("waiting %s...(%d)\n", tty_name(tty), tty->driver.chars_in_buffer(tty)); + printk("waiting %s...(%d)\n", tty_name(tty, buf), + tty->driver.chars_in_buffer(tty)); #endif current->state = TASK_INTERRUPTIBLE; if (signal_pending(current)) diff -ur --new-file old/linux/drivers/char/tuner.h new/linux/drivers/char/tuner.h --- old/linux/drivers/char/tuner.h Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/char/tuner.h Wed Jan 14 05:14:36 1998 @@ -54,6 +54,7 @@ unchar UHF; unchar config; unchar I2C; + ushort IFPCoff; }; #endif 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 Dec 29 19:27:23 1997 +++ new/linux/drivers/char/vc_screen.c Tue Feb 10 01:12:55 1998 @@ -16,8 +16,7 @@ * aeb@cwi.nl - efter Friedas begravelse - 950211 * * machek@k332.feld.cvut.cz - modified not to send characters to wrong console - * - fixed some fatal of-by-one bugs (0-- no longer == -1 -> looping and looping and looping...) - * - making it working with multiple monitor patches + * - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...) * - making it shorter - scr_readw are macros which expand in PRETTY long code */ @@ -76,24 +75,22 @@ static long long vcs_lseek(struct file *file, long long offset, int orig) { - int size; - size = vcs_size(file->f_dentry->d_inode); + int size = vcs_size(file->f_dentry->d_inode); switch (orig) { - case 0: - file->f_pos = offset; + default: + return -EINVAL; + case 2: + offset += size; break; case 1: - file->f_pos += offset; - break; - case 2: - file->f_pos = size + offset; + offset += file->f_pos; + case 0: break; - default: - return -EINVAL; } - if (file->f_pos < 0 || file->f_pos > size) - { file->f_pos = 0; return -EINVAL; } + if (offset < 0 || offset > size) + return -EINVAL; + file->f_pos = offset; return file->f_pos; } diff -ur --new-file old/linux/drivers/char/videodev.c new/linux/drivers/char/videodev.c --- old/linux/drivers/char/videodev.c Mon Jan 12 23:46:16 1998 +++ new/linux/drivers/char/videodev.c Sat Jan 24 02:38:04 1998 @@ -36,17 +36,15 @@ static struct video_device *video_device[VIDEO_NUM_DEVICES]; -/* - * Initialiser list - */ - -struct video_init -{ - char *name; - int (*init)(struct video_init *); -}; - +#ifdef CONFIG_VIDEO_BT848 extern int init_bttv_cards(struct video_init *); +#endif +#ifdef CONFIG_VIDEO_CQCAM +extern int init_colour_qcams(struct video_init *); +#endif +#ifdef CONFIG_VIDEO_BWQCAM +extern int init_bw_qcams(struct video_init *); +#endif static struct video_init video_init_list[]={ #ifdef CONFIG_VIDEO_BT848 @@ -59,7 +57,7 @@ {"bw-qcam", init_bw_qcams}, #endif #ifdef CONFIG_VIDEO_PMS - {"PMS", init_pms_cards}, + {"PMS", init_pms_cards}, /* not defined anywhere */ #endif {"end", NULL} }; @@ -72,7 +70,6 @@ static ssize_t video_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - int err; struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK); } @@ -85,7 +82,6 @@ static ssize_t video_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - int err; struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK); } diff -ur --new-file old/linux/drivers/isdn/Makefile new/linux/drivers/isdn/Makefile --- old/linux/drivers/isdn/Makefile Fri May 30 06:53:05 1997 +++ new/linux/drivers/isdn/Makefile Fri Jan 16 20:18:09 1998 @@ -47,7 +47,7 @@ endif ifeq ($(CONFIG_ISDN_DRV_ICN),y) - L_OBJS += icn/icn.o + L_OBJS += icn/icn_obj.o SUB_DIRS += icn MOD_SUB_DIRS += icn else diff -ur --new-file old/linux/drivers/isdn/avmb1/b1capi.c new/linux/drivers/isdn/avmb1/b1capi.c --- old/linux/drivers/isdn/avmb1/b1capi.c Sat Sep 20 23:51:54 1997 +++ new/linux/drivers/isdn/avmb1/b1capi.c Tue Feb 10 22:07:50 1998 @@ -52,10 +52,11 @@ /* ------------------------------------------------------------- */ -int portbase = 0x150; -int irq = 15; int showcapimsgs = 0; /* used in lli.c */ int loaddebug = 0; +static int portbase = 0x150; +#ifdef MODULE +static int irq = 15; #ifdef HAS_NEW_SYMTAB MODULE_AUTHOR("Carsten Paeth "); @@ -64,6 +65,7 @@ MODULE_PARM(showcapimsgs, "0-3i"); MODULE_PARM(loaddebug, "0-1i"); #endif +#endif /* ------------------------------------------------------------- */ @@ -298,13 +300,13 @@ if (!VALID_APPLID(appl)) { printk(KERN_ERR "b1capi: recv_handler: applid %d ? (%s)\n", appl, capi_message2str(skb->data)); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); continue; } if (APPL(appl)->signal == 0) { printk(KERN_ERR "b1capi: recv_handler: applid %d has no signal function\n", appl); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); continue; } if ( CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3 @@ -334,7 +336,7 @@ return; error: - kfree_skb(skb, FREE_READ); + kfree_skb(skb); } void avmb1_interrupt(int interrupt, void *devptr, struct pt_regs *regs) @@ -535,7 +537,7 @@ if (!VALID_APPLID(applid) || APPL(applid)->releasing) return CAPI_ILLAPPNR; while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0) - kfree_skb(skb, FREE_READ); + kfree_skb(skb); for (i = 0; i < ncards; i++) { if (cards[i].cardstate != CARD_RUNNING) continue; diff -ur --new-file old/linux/drivers/isdn/avmb1/b1lli.c new/linux/drivers/isdn/avmb1/b1lli.c --- old/linux/drivers/isdn/avmb1/b1lli.c Fri May 30 06:53:05 1997 +++ new/linux/drivers/isdn/avmb1/b1lli.c Tue Feb 10 22:07:50 1998 @@ -456,7 +456,7 @@ B1_put_slice(port, skb->data, len); restore_flags(flags); } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } /* diff -ur --new-file old/linux/drivers/isdn/avmb1/capi.c new/linux/drivers/isdn/avmb1/capi.c --- old/linux/drivers/isdn/avmb1/capi.c Tue Dec 9 08:58:04 1997 +++ new/linux/drivers/isdn/avmb1/capi.c Fri Feb 27 18:11:27 1998 @@ -144,7 +144,7 @@ copied = skb->len; - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return copied; } @@ -169,7 +169,7 @@ skb = alloc_skb(count, GFP_USER); if ((retval = copy_from_user(skb_put(skb, count), buf, count))) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return retval; } cmd = CAPIMSG_COMMAND(skb->data); @@ -178,11 +178,11 @@ if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) { __u16 dlen = CAPIMSG_DATALEN(skb->data); if (mlen + dlen != count) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return -EINVAL; } } else if (mlen != count) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return -EINVAL; } CAPIMSG_SETAPPID(skb->data, cdev->applid); @@ -190,7 +190,7 @@ cdev->errcode = (*capifuncs->capi_put_message) (cdev->applid, skb); if (cdev->errcode) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return -EIO; } return count; @@ -207,7 +207,7 @@ return POLLERR; cdev = &capidevs[minor]; - poll_wait(&(cdev->recv_wait), wait); + poll_wait(file, &(cdev->recv_wait), wait); mask = POLLOUT | POLLWRNORM; if (!skb_queue_empty(&cdev->recv_queue)) mask |= POLLIN | POLLRDNORM; @@ -416,7 +416,7 @@ cdev->applid = 0; while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) - kfree_skb(skb, FREE_READ); + kfree_skb(skb); } cdev->is_open = 0; diff -ur --new-file old/linux/drivers/isdn/avmb1/capidrv.c new/linux/drivers/isdn/avmb1/capidrv.c --- old/linux/drivers/isdn/avmb1/capidrv.c Fri May 30 06:53:05 1997 +++ new/linux/drivers/isdn/avmb1/capidrv.c Tue Feb 10 22:07:50 1998 @@ -1169,7 +1169,7 @@ printk(KERN_ERR "capidrv: %s: ncci 0x%x not found\n", capi_cmd2str(cmsg->Command, cmsg->Subcommand), cmsg->adr.adrNCCI); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return; } (void) skb_pull(skb, CAPIMSG_LEN(skb->data)); @@ -1194,7 +1194,7 @@ handle_data(&s_cmsg, skb); continue; } - kfree_skb(skb, FREE_READ); + kfree_skb(skb); if ((s_cmsg.adr.adrController & 0xffffff00) == 0) handle_controller(&s_cmsg); else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0) @@ -1517,10 +1517,10 @@ errcode = (*capifuncs->capi_put_message) (global.appid, nskb); switch (errcode) { case CAPI_NOERROR: - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return len; case CAPI_SENDQUEUEFULL: - dev_kfree_skb(nskb, FREE_WRITE); + dev_kfree_skb(nskb); return 0; default: return -1; diff -ur --new-file old/linux/drivers/isdn/hisax/avm_a1.c new/linux/drivers/isdn/hisax/avm_a1.c --- old/linux/drivers/isdn/hisax/avm_a1.c Mon Nov 3 18:54:38 1997 +++ new/linux/drivers/isdn/hisax/avm_a1.c Tue Feb 10 22:07:50 1998 @@ -277,7 +277,7 @@ return; } else { SET_SKB_FREE(hsp->tx_skb); - dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + dev_kfree_skb(hsp->tx_skb); hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); @@ -439,7 +439,7 @@ goto afterXPR; } else { SET_SKB_FREE(sp->tx_skb); - dev_kfree_skb(sp->tx_skb, FREE_WRITE); + dev_kfree_skb(sp->tx_skb); sp->tx_cnt = 0; sp->tx_skb = NULL; } @@ -772,7 +772,7 @@ int loop = 0; char tmp[40]; - sp->counter = kstat.interrupts[sp->irq]; + sp->counter = kstat_irqs(sp->irq); sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); debugl1(sp, tmp); clear_pending_ints(sp); @@ -785,16 +785,16 @@ /* At least 1-3 irqs must happen * (one from HSCX A, one from HSCX B, 3rd from ISAC) */ - if (kstat.interrupts[sp->irq] > sp->counter) + if (kstat_irqs(sp->irq) > sp->counter) break; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 1; schedule(); } sprintf(tmp, "IRQ %d count %d", sp->irq, - kstat.interrupts[sp->irq]); + kstat_irqs(sp->irq)); debugl1(sp, tmp); - if (kstat.interrupts[sp->irq] == sp->counter) { + if (kstat_irqs(sp->irq) == sp->counter) { printk(KERN_WARNING "AVM A1: IRQ(%d) getting no interrupts during init\n", sp->irq); diff -ur --new-file old/linux/drivers/isdn/hisax/buffers.c new/linux/drivers/isdn/hisax/buffers.c --- old/linux/drivers/isdn/hisax/buffers.c Thu Feb 27 19:57:29 1997 +++ new/linux/drivers/isdn/hisax/buffers.c Sat Jan 17 05:35:48 1998 @@ -53,7 +53,7 @@ printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp); #endif - ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0); + ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder); if (!ptr) { printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n"); return (-1); diff -ur --new-file old/linux/drivers/isdn/hisax/callc.c new/linux/drivers/isdn/hisax/callc.c --- old/linux/drivers/isdn/hisax/callc.c Tue Jun 17 01:35:55 1997 +++ new/linux/drivers/isdn/hisax/callc.c Tue Feb 10 22:07:50 1998 @@ -1600,7 +1600,7 @@ chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb); else { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } break; default: @@ -1622,7 +1622,7 @@ chanp->sp->iif.rcvcallb_skb(chanp->sp->myid, chanp->chan, skb); else { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } break; default: @@ -1966,7 +1966,7 @@ csta->hs[chanp->hscx].tx_cnt += len; chanp->ds.l2.l2l1(&chanp->ds, PH_DATA, nskb); } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } else len = 0; restore_flags(flags); 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 Fri May 30 06:53:05 1997 +++ new/linux/drivers/isdn/hisax/config.c Sun Jan 25 19:05:46 1998 @@ -179,23 +179,23 @@ char *HiSax_id = HiSaxID; #ifdef MODULE /* Variables for insmod */ -int type[] = +static int type[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -int protocol[] = +static int protocol[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -int io[] = +static int io[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; #ifdef CONFIG_HISAX_16_3 /* For Creatix/Teles PnP */ -int io0[] = +static int io0[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -int io1[] = +static int io1[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; #endif -int irq[] = +static int irq[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -int mem[] = +static int mem[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -char *id = HiSaxID; +static char *id = HiSaxID; #if (LINUX_VERSION_CODE > 0x020111) MODULE_AUTHOR("Karsten Keil"); diff -ur --new-file old/linux/drivers/isdn/hisax/elsa.c new/linux/drivers/isdn/hisax/elsa.c --- old/linux/drivers/isdn/hisax/elsa.c Mon Nov 3 18:54:38 1997 +++ new/linux/drivers/isdn/hisax/elsa.c Tue Feb 10 22:07:50 1998 @@ -488,7 +488,7 @@ return; } else { SET_SKB_FREE(hsp->tx_skb); - dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + dev_kfree_skb(hsp->tx_skb); hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); @@ -653,7 +653,7 @@ goto afterXPR; } else { SET_SKB_FREE(sp->tx_skb); - dev_kfree_skb(sp->tx_skb, FREE_WRITE); + dev_kfree_skb(sp->tx_skb); sp->tx_cnt = 0; sp->tx_skb = NULL; } @@ -1180,7 +1180,7 @@ int ret, irq_cnt, cnt = 3; long flags; - irq_cnt = kstat.interrupts[sp->irq]; + irq_cnt = kstat_irqs(sp->irq); printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, irq_cnt); ret = get_irq(sp->cardnr, &elsa_interrupt); #ifdef CONFIG_HISAX_ELSA_PCC @@ -1213,8 +1213,8 @@ } #endif printk(KERN_INFO "Elsa: IRQ %d count %d\n", sp->irq, - kstat.interrupts[sp->irq]); - if (kstat.interrupts[sp->irq] == irq_cnt) { + kstat_irqs(sp->irq)); + if (kstat_irqs(sp->irq) == irq_cnt) { printk(KERN_WARNING "Elsa: IRQ(%d) getting no interrupts during init %d\n", sp->irq, 4 - cnt); 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 Mon Nov 3 18:54:38 1997 +++ new/linux/drivers/isdn/hisax/isdnl1.c Tue Feb 10 22:07:50 1998 @@ -453,7 +453,7 @@ stptr = stptr->next; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } else { found = 0; while (stptr != NULL) @@ -478,7 +478,7 @@ dlogframe(sp, skb->data + 4, skb->len - 4, tmp); } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } } @@ -714,7 +714,7 @@ while ((skb = skb_dequeue(&sp->sq))) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } } @@ -798,15 +798,15 @@ } while ((skb = skb_dequeue(&hs->rqueue))) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } while ((skb = skb_dequeue(&hs->squeue))) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } if (hs->tx_skb) { SET_SKB_FREE(hs->tx_skb); - dev_kfree_skb(hs->tx_skb, FREE_WRITE); + dev_kfree_skb(hs->tx_skb); hs->tx_skb = NULL; } } @@ -828,15 +828,15 @@ } while ((skb = skb_dequeue(&csta->rq))) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } while ((skb = skb_dequeue(&csta->sq))) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } if (csta->tx_skb) { SET_SKB_FREE(csta->tx_skb); - dev_kfree_skb(csta->tx_skb, FREE_WRITE); + dev_kfree_skb(csta->tx_skb); csta->tx_skb = NULL; } switch (csta->typ) { @@ -1219,7 +1219,7 @@ while ((skb = skb_dequeue(&hsp->squeue))) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } } diff -ur --new-file old/linux/drivers/isdn/hisax/isdnl2.c new/linux/drivers/isdn/hisax/isdnl2.c --- old/linux/drivers/isdn/hisax/isdnl2.c Fri May 30 06:53:06 1997 +++ new/linux/drivers/isdn/hisax/isdnl2.c Tue Feb 10 22:07:50 1998 @@ -148,7 +148,7 @@ if (l2->windowar[i]) { cnt++; SET_SKB_FREE(l2->windowar[i]); - dev_kfree_skb(l2->windowar[i], FREE_WRITE); + dev_kfree_skb(l2->windowar[i]); l2->windowar[i] = NULL; } } @@ -172,7 +172,7 @@ while ((skb = skb_dequeue(&st->l2.i_queue))) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } } @@ -248,7 +248,7 @@ while (l2->va != nr) { l2->va = (l2->va + 1) % (l2->extended ? 128 : 8); SET_SKB_FREE(l2->windowar[l2->sow]); - dev_kfree_skb(l2->windowar[l2->sow], FREE_WRITE); + dev_kfree_skb(l2->windowar[l2->sow]); l2->windowar[l2->sow] = NULL; l2->sow = (l2->sow + 1) % l2->window; if (st->l4.l2writewakeup) @@ -369,7 +369,7 @@ skb_pull(skb, l2addrsize(&(st->l2))); PollFlag = *skb->data & 0x10; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (ST_L2_4 != state) if (st->l2.vs != st->l2.va) { @@ -414,7 +414,7 @@ skb_pull(skb, l2addrsize(&(st->l2))); PollFlag = *skb->data & 0x10; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); FsmChangeState(fi, ST_L2_4); @@ -440,7 +440,7 @@ skb_pull(skb, l2addrsize(&(st->l2))); PollFlag = *skb->data & 0x10; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (!((chanp->impair == 1) && (st->l2.laptype == LAPB))) send_uframe(st, DM | (PollFlag ? 0x10 : 0x0), RSP); @@ -457,7 +457,7 @@ skb_pull(skb, l2addrsize(&(st->l2))); f = *skb->data & 0x10; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (f) { st->l2.vs = 0; st->l2.va = 0; @@ -484,7 +484,7 @@ skb_pull(skb, l2addrsize(&(st->l2))); f = *skb->data & 0x10; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (f) { FsmDelTimer(&st->l2.t200_timer, 6); FsmChangeState(fi, ST_L2_4); @@ -560,7 +560,7 @@ seq = (skb->data[0] >> 5) & 0x7; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (!((chanp->impair == 4) && (st->l2.laptype == LAPB))) if ((!rsp) && PollFlag) @@ -649,7 +649,7 @@ /* n(s)!=v(r) */ wasok = 0; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (st->l2.rejexp) { if (p) if (!((chanp->impair == 3) && (st->l2.laptype == LAPB))) @@ -779,7 +779,7 @@ seq = (skb->data[0] >> 5) & 0x7; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if ((!rsp) && PollFlag) enquiry_response(st, RR, PollFlag); @@ -866,7 +866,7 @@ printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", p1); SET_SKB_FREE(l2->windowar[p1]); - dev_kfree_skb(l2->windowar[p1], FREE_WRITE); + dev_kfree_skb(l2->windowar[p1]); } l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC); @@ -944,7 +944,7 @@ seq = (skb->data[0] >> 5) & 0x7; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (rsp && PollFlag) { if (legalnr(st, seq)) { @@ -1019,7 +1019,7 @@ l2m_debug(&st->l2.l2m, tmp); } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } static void @@ -1193,7 +1193,7 @@ if (ret) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } break; case (PH_PULL_ACK): @@ -1209,13 +1209,13 @@ case (DL_DATA): if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) { SET_SKB_FREE(((struct sk_buff *) arg)); - dev_kfree_skb((struct sk_buff *) arg, FREE_READ); + dev_kfree_skb((struct sk_buff *) arg); } break; case (DL_UNIT_DATA): if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) { SET_SKB_FREE(((struct sk_buff *) arg)); - dev_kfree_skb((struct sk_buff *) arg, FREE_READ); + dev_kfree_skb((struct sk_buff *) arg); } break; } diff -ur --new-file old/linux/drivers/isdn/hisax/isdnl3.c new/linux/drivers/isdn/hisax/isdnl3.c --- old/linux/drivers/isdn/hisax/isdnl3.c Fri May 30 06:53:06 1997 +++ new/linux/drivers/isdn/hisax/isdnl3.c Tue Feb 10 22:07:50 1998 @@ -135,7 +135,7 @@ l3_debug(st, "no protocol"); if (skb) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } } diff -ur --new-file old/linux/drivers/isdn/hisax/ix1_micro.c new/linux/drivers/isdn/hisax/ix1_micro.c --- old/linux/drivers/isdn/hisax/ix1_micro.c Mon Nov 3 18:54:38 1997 +++ new/linux/drivers/isdn/hisax/ix1_micro.c Tue Feb 10 22:07:50 1998 @@ -363,7 +363,7 @@ return; } else { SET_SKB_FREE(hsp->tx_skb); - dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + dev_kfree_skb(hsp->tx_skb); hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); @@ -526,7 +526,7 @@ goto afterXPR; } else { SET_SKB_FREE(sp->tx_skb); - dev_kfree_skb(sp->tx_skb, FREE_WRITE); + dev_kfree_skb(sp->tx_skb); sp->tx_cnt = 0; sp->tx_skb = NULL; } @@ -841,7 +841,7 @@ int loop = 0; char tmp[40]; - sp->counter = kstat.interrupts[sp->irq]; + sp->counter = kstat_irqs(sp->irq); sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); debugl1(sp, tmp); clear_pending_ints(sp); @@ -854,16 +854,16 @@ /* At least 1-3 irqs must happen * (one from HSCX A, one from HSCX B, 3rd from ISAC) */ - if (kstat.interrupts[sp->irq] > sp->counter) + if (kstat_irqs(sp->irq) > sp->counter) break; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 1; schedule(); } sprintf(tmp, "IRQ %d count %d", sp->irq, - kstat.interrupts[sp->irq]); + kstat_irqs(sp->irq)); debugl1(sp, tmp); - if (kstat.interrupts[sp->irq] == sp->counter) { + if (kstat_irqs(sp->irq) == sp->counter) { printk(KERN_WARNING "ix1-Micro: IRQ(%d) getting no interrupts during init\n", sp->irq); diff -ur --new-file old/linux/drivers/isdn/hisax/l3_1tr6.c new/linux/drivers/isdn/hisax/l3_1tr6.c --- old/linux/drivers/isdn/hisax/l3_1tr6.c Wed Aug 6 22:02:58 1997 +++ new/linux/drivers/isdn/hisax/l3_1tr6.c Tue Feb 10 22:07:50 1998 @@ -209,7 +209,7 @@ st->pa->spv = 1; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); /* Signal all services, linklevel takes care of Service-Indicator */ if (bcfound) { @@ -238,7 +238,7 @@ } else if (st->l3.debug & L3_DEB_WARN) l3_debug(st, "setup answer without bchannel"); SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304); st->l3.l3l4(st, CC_MORE_INFO, NULL); } @@ -256,7 +256,7 @@ } else if (st->l3.debug & L3_DEB_WARN) l3_debug(st, "setup answer without bchannel"); SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310); newl3state(st, 3); st->l3.l3l4(st, CC_PROCEEDING_IND, NULL); @@ -268,7 +268,7 @@ struct sk_buff *skb = arg; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); L3DelTimer(&st->l3.timer); /* T304 */ newl3state(st, 4); st->l3.l3l4(st, CC_ALERTING_IND, NULL); @@ -300,7 +300,7 @@ } else if (st->l3.debug & L3_DEB_CHARGE) l3_debug(st, "charging info not found"); SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } @@ -310,7 +310,7 @@ struct sk_buff *skb = arg; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } static void @@ -321,7 +321,7 @@ L3DelTimer(&st->l3.timer); /* T310 */ newl3state(st, 10); SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); st->pa->chargeinfo = 0; st->l3.l3l4(st, CC_SETUP_CNF, NULL); } @@ -347,7 +347,7 @@ } else st->pa->cause = -1; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); StopAllL3Timer(st); newl3state(st, 0); l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1); @@ -360,7 +360,7 @@ struct sk_buff *skb = arg; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); StopAllL3Timer(st); newl3state(st, 0); st->pa->cause = -1; @@ -413,7 +413,7 @@ st->pa->cause = -1; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); newl3state(st, 12); st->l3.l3l4(st, CC_DISCONNECT_IND, NULL); } @@ -425,7 +425,7 @@ struct sk_buff *skb = arg; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); newl3state(st, 10); st->pa->chargeinfo = 0; L3DelTimer(&st->l3.timer); @@ -706,13 +706,13 @@ l3_debug(st, tmp); } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); return; } mt = skb->data[skb->data[1] + 2]; if (skb->data[0] == PROTO_DIS_N0) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%s N0 state %d mt %x unhandled", (pr == DL_DATA) ? " " : "(broadcast) ", @@ -726,7 +726,7 @@ break; if (i == datastln1_len) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", (pr == DL_DATA) ? " " : "(broadcast) ", diff -ur --new-file old/linux/drivers/isdn/hisax/l3dss1.c new/linux/drivers/isdn/hisax/l3dss1.c --- old/linux/drivers/isdn/hisax/l3dss1.c Wed Aug 6 22:02:58 1997 +++ new/linux/drivers/isdn/hisax/l3dss1.c Tue Feb 10 22:07:50 1998 @@ -110,7 +110,7 @@ cause = *p & 0x7f; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); StopAllL3Timer(st); st->pa->cause = cause; newl3state(st, 0); @@ -238,7 +238,7 @@ } else if (st->l3.debug & L3_DEB_WARN) l3_debug(st, "setup answer without bchannel"); SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); newl3state(st, 3); L3AddTimer(&st->l3.timer, st->l3.t310, CC_T310); st->l3.l3l4(st, CC_PROCEEDING_IND, NULL); @@ -259,7 +259,7 @@ } else if (st->l3.debug & L3_DEB_WARN) l3_debug(st, "setup answer without bchannel"); SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); newl3state(st, 2); L3AddTimer(&st->l3.timer, st->l3.t304, CC_T304); st->l3.l3l4(st, CC_MORE_INFO, NULL); @@ -282,7 +282,7 @@ cause = *p & 0x7f; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); newl3state(st, 12); st->pa->cause = cause; st->l3.l3l4(st, CC_DISCONNECT_IND, NULL); @@ -294,7 +294,7 @@ struct sk_buff *skb = arg; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); L3DelTimer(&st->l3.timer); /* T310 */ newl3state(st, 10); st->l3.l3l4(st, CC_SETUP_CNF, NULL); @@ -306,7 +306,7 @@ struct sk_buff *skb = arg; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); L3DelTimer(&st->l3.timer); /* T304 */ newl3state(st, 4); st->l3.l3l4(st, CC_ALERTING_IND, NULL); @@ -394,7 +394,7 @@ st->pa->setup.screen = 0; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (bcfound) { if ((st->pa->setup.si1 != 7) && (st->l3.debug & L3_DEB_WARN)) { @@ -431,7 +431,7 @@ struct sk_buff *skb = arg; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); newl3state(st, 10); L3DelTimer(&st->l3.timer); st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL); @@ -510,7 +510,7 @@ cause = *p & 0x7f; } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); StopAllL3Timer(st); st->pa->cause = cause; newl3state(st, 0); @@ -535,7 +535,7 @@ struct sk_buff *skb = arg; SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); MsgHead(p, st->l3.callref, MT_STATUS); @@ -727,7 +727,7 @@ l3_debug(st, tmp); } SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); return; } mt = skb->data[skb->data[1] + 2]; @@ -737,7 +737,7 @@ break; if (i == datasllen) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); if (st->l3.debug & L3_DEB_STATE) { sprintf(tmp, "dss1up%sstate %d mt %x unhandled", (pr == DL_DATA) ? " " : "(broadcast) ", diff -ur --new-file old/linux/drivers/isdn/hisax/tei.c new/linux/drivers/isdn/hisax/tei.c --- old/linux/drivers/isdn/hisax/tei.c Fri May 30 06:53:06 1997 +++ new/linux/drivers/isdn/hisax/tei.c Tue Feb 10 22:07:50 1998 @@ -233,7 +233,7 @@ } else mdl_unit_data_ind(st, (bp[1] << 8) | bp[2], bp[3], bp[4] >> 1); SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); break; default: break; diff -ur --new-file old/linux/drivers/isdn/hisax/teles0.c new/linux/drivers/isdn/hisax/teles0.c --- old/linux/drivers/isdn/hisax/teles0.c Mon Nov 3 18:54:38 1997 +++ new/linux/drivers/isdn/hisax/teles0.c Tue Feb 10 22:07:50 1998 @@ -327,7 +327,7 @@ return; } else { SET_SKB_FREE(hsp->tx_skb); - dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + dev_kfree_skb(hsp->tx_skb); hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); @@ -487,7 +487,7 @@ goto afterXPR; } else { SET_SKB_FREE(sp->tx_skb); - dev_kfree_skb(sp->tx_skb, FREE_WRITE); + dev_kfree_skb(sp->tx_skb); sp->tx_cnt = 0; sp->tx_skb = NULL; } @@ -802,7 +802,7 @@ int loop = 0; char tmp[40]; - sp->counter = kstat.interrupts[sp->irq]; + sp->counter = kstat_irqs(sp->irq); sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); debugl1(sp, tmp); clear_pending_ints(sp); @@ -815,16 +815,16 @@ /* At least 1-3 irqs must happen * (one from HSCX A, one from HSCX B, 3rd from ISAC) */ - if (kstat.interrupts[sp->irq] > sp->counter) + if (kstat_irqs(sp->irq) > sp->counter) break; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 1; schedule(); } sprintf(tmp, "IRQ %d count %d", sp->irq, - kstat.interrupts[sp->irq]); + kstat_irqs(sp->irq)); debugl1(sp, tmp); - if (kstat.interrupts[sp->irq] == sp->counter) { + if (kstat_irqs(sp->irq) == sp->counter) { printk(KERN_WARNING "Teles0: IRQ(%d) getting no interrupts during init\n", sp->irq); diff -ur --new-file old/linux/drivers/isdn/hisax/teles3.c new/linux/drivers/isdn/hisax/teles3.c --- old/linux/drivers/isdn/hisax/teles3.c Mon Nov 3 18:54:38 1997 +++ new/linux/drivers/isdn/hisax/teles3.c Tue Feb 10 22:07:50 1998 @@ -303,7 +303,7 @@ return; } else { SET_SKB_FREE(hsp->tx_skb); - dev_kfree_skb(hsp->tx_skb, FREE_WRITE); + dev_kfree_skb(hsp->tx_skb); hsp->count = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); @@ -465,7 +465,7 @@ goto afterXPR; } else { SET_SKB_FREE(sp->tx_skb); - dev_kfree_skb(sp->tx_skb, FREE_WRITE); + dev_kfree_skb(sp->tx_skb); sp->tx_cnt = 0; sp->tx_skb = NULL; } @@ -801,7 +801,7 @@ int loop = 0; char tmp[40]; - sp->counter = kstat.interrupts[sp->irq]; + sp->counter = kstat_irqs(sp->irq); sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter); debugl1(sp, tmp); clear_pending_ints(sp); @@ -816,16 +816,16 @@ /* At least 1-3 irqs must happen * (one from HSCX A, one from HSCX B, 3rd from ISAC) */ - if (kstat.interrupts[sp->irq] > sp->counter) + if (kstat_irqs(sp->irq) > sp->counter) break; current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + 1; schedule(); } sprintf(tmp, "IRQ %d count %d loop %d", sp->irq, - kstat.interrupts[sp->irq], loop); + kstat_irqs(sp->irq), loop); debugl1(sp, tmp); - if (kstat.interrupts[sp->irq] <= sp->counter) { + if (kstat_irqs(sp->irq) <= sp->counter) { printk(KERN_WARNING "Teles3: IRQ(%d) getting no interrupts during init\n", sp->irq); diff -ur --new-file old/linux/drivers/isdn/icn/Makefile new/linux/drivers/isdn/icn/Makefile --- old/linux/drivers/isdn/icn/Makefile Mon Feb 26 10:58:04 1996 +++ new/linux/drivers/isdn/icn/Makefile Fri Jan 16 20:18:09 1998 @@ -1,11 +1,8 @@ -L_OBJS := -M_OBJS := - ifeq ($(CONFIG_ISDN_DRV_ICN),y) - L_OBJS += icn.o + O_TARGET := icn_obj.o + O_OBJS := icn.o else - M_OBJS += icn.o + M_OBJS := icn.o endif include $(TOPDIR)/Rules.make - diff -ur --new-file old/linux/drivers/isdn/icn/icn.c new/linux/drivers/isdn/icn/icn.c --- old/linux/drivers/isdn/icn/icn.c Fri May 30 06:53:06 1997 +++ new/linux/drivers/isdn/icn/icn.c Tue Feb 10 22:07:50 1998 @@ -207,7 +207,7 @@ struct sk_buff *skb; while ((skb = skb_dequeue(queue))) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); card->sndcount[channel] = 0; } @@ -471,7 +471,7 @@ sbnext; /* switch to next buffer */ icn_maprelease_channel(card, mch & 2); if (!skb->len) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); cmd.command = ISDN_STAT_BSENT; cmd.driver = card->myid; cmd.arg = channel; @@ -828,7 +828,7 @@ nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { skb_queue_tail(&card->spqueue[channel], nskb); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } else len = 0; card->sndcount[channel] += len; diff -ur --new-file old/linux/drivers/isdn/isdn_audio.c new/linux/drivers/isdn/isdn_audio.c --- old/linux/drivers/isdn/isdn_audio.c Fri May 30 06:53:06 1997 +++ new/linux/drivers/isdn/isdn_audio.c Tue Feb 10 22:07:50 1998 @@ -596,7 +596,7 @@ if (skb_headroom(skb) < sizeof(isdn_audio_skb)) { printk(KERN_WARNING "isdn_audio: insufficient skb_headroom, dropping\n"); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return; } ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; @@ -613,7 +613,7 @@ isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); } else - kfree_skb(skb, FREE_READ); + kfree_skb(skb); s->last = what; } } diff -ur --new-file old/linux/drivers/isdn/isdn_common.c new/linux/drivers/isdn/isdn_common.c --- old/linux/drivers/isdn/isdn_common.c Tue Dec 9 08:58:04 1997 +++ new/linux/drivers/isdn/isdn_common.c Fri Feb 27 05:00:42 1998 @@ -261,10 +261,10 @@ #endif static __inline void -isdn_trash_skb(struct sk_buff *skb, int rw) +isdn_trash_skb(struct sk_buff *skb) { SET_SKB_FREE(skb); - kfree_skb(skb, rw); + kfree_skb(skb); } static void @@ -277,7 +277,7 @@ cli(); if (skb_queue_len(queue)) while ((skb = skb_dequeue(queue))) - isdn_trash_skb(skb, FREE_READ); + isdn_trash_skb(skb); restore_flags(flags); } @@ -374,7 +374,7 @@ int i; if ((i = isdn_dc2minor(di, channel)) == -1) { - isdn_trash_skb(skb, FREE_READ); + isdn_trash_skb(skb); return; } /* Update statistics */ @@ -389,7 +389,7 @@ return; wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]); } else - isdn_trash_skb(skb, FREE_READ); + isdn_trash_skb(skb); } void @@ -752,7 +752,7 @@ ISDN_AUDIO_SKB_LOCK(skb) = 0; #endif skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); - isdn_trash_skb(skb, FREE_READ); + isdn_trash_skb(skb); } else { /* Not yet emptied this buff, so it * must stay in the queue, for further calls @@ -1015,7 +1015,7 @@ int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (minor == ISDN_MINOR_STATUS) { - poll_wait(&(dev->info_waitq), wait); + poll_wait(file, &(dev->info_waitq), wait); /* mask = POLLOUT | POLLWRNORM; */ if (file->private_data) { mask |= POLLIN | POLLRDNORM; @@ -1023,7 +1023,7 @@ return mask; } if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { - poll_wait(&(dev->drv[drvidx]->st_waitq), wait); + poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); if (drvidx < 0) { printk(KERN_ERR "isdn_common: isdn_poll 1 -> what the hell\n"); return POLLERR; @@ -1892,7 +1892,7 @@ ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, skb); if (ret <= 0) - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); } if (ret > 0) dev->obytes[isdn_dc2minor(drvidx, chan)] += ret; @@ -1919,7 +1919,7 @@ else { if ((ret = dev->drv[drvidx]->interface-> writebuf(drvidx, chan, skb->data, skb->len, 0)) == len) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } if (ret > 0) dev->obytes[isdn_dc2minor(drvidx, chan)] += len; diff -ur --new-file old/linux/drivers/isdn/isdn_net.c new/linux/drivers/isdn/isdn_net.c --- old/linux/drivers/isdn/isdn_net.c Mon Dec 29 19:22:42 1997 +++ new/linux/drivers/isdn/isdn_net.c Tue Feb 10 22:07:50 1998 @@ -303,11 +303,11 @@ save_flags(flags); cli(); if (lp->first_skb) { - dev_kfree_skb(lp->first_skb, FREE_WRITE); + dev_kfree_skb(lp->first_skb); lp->first_skb = NULL; } if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb, FREE_WRITE); + dev_kfree_skb(lp->sav_skb); lp->sav_skb = NULL; } #ifdef DEV_NUMBUFFS @@ -452,11 +452,11 @@ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { lp->flags &= ~ISDN_NET_CONNECTED; if (lp->first_skb) { - dev_kfree_skb(lp->first_skb, FREE_WRITE); + dev_kfree_skb(lp->first_skb); lp->first_skb = NULL; } if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb, FREE_WRITE); + dev_kfree_skb(lp->sav_skb); lp->sav_skb = NULL; } isdn_free_channel(lp->isdn_device, lp->isdn_channel, @@ -912,7 +912,7 @@ } if (ret < 0) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); lp->stats.tx_errors++; clear_bit(0, (void *) &(ndev->tbusy)); return 0; @@ -1043,7 +1043,7 @@ #else isdn_net_unreachable(ndev, skb, "No channel"); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); ndev->tbusy = 0; return 0; #endif @@ -1059,7 +1059,7 @@ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { /* no 'first_skb' handling for syncPPP */ if (isdn_ppp_bind(lp) < 0) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); isdn_net_unbind_channel(lp); restore_flags(flags); return 0; /* STN (skb to nirvana) ;) */ @@ -1074,7 +1074,7 @@ */ if (lp->first_skb) { printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n"); - dev_kfree_skb(lp->first_skb, FREE_WRITE); + dev_kfree_skb(lp->first_skb); lp->first_skb = NULL; } lp->first_skb = skb; @@ -1086,7 +1086,7 @@ } else { isdn_net_unreachable(ndev, skb, "No phone number"); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); ndev->tbusy = 0; return 0; } @@ -1272,7 +1272,7 @@ default: printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", lp->name); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return; } netif_rx(skb); @@ -2610,7 +2610,7 @@ for (i = 0; i < DEV_NUMBUFFS; i++) { struct sk_buff *skb; while ((skb = skb_dequeue(&dev->buffs[i]))) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } } diff -ur --new-file old/linux/drivers/isdn/isdn_ppp.c new/linux/drivers/isdn/isdn_ppp.c --- old/linux/drivers/isdn/isdn_ppp.c Tue Dec 9 08:58:04 1997 +++ new/linux/drivers/isdn/isdn_ppp.c Fri Feb 27 05:00:52 1998 @@ -702,7 +702,7 @@ if (is->debug & 0x2) printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", MINOR(file->f_dentry->d_inode->i_rdev)); - poll_wait(&is->wq, wait); + poll_wait(file, &is->wq, wait); if (!(is->state & IPPP_OPEN)) { printk(KERN_DEBUG "isdn_ppp: device not open\n"); @@ -881,7 +881,7 @@ } if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb)) != count) { if (lp->sav_skb) { - dev_kfree_skb(lp->sav_skb, FREE_WRITE); + dev_kfree_skb(lp->sav_skb); printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count); } else printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", cnt, count); @@ -955,7 +955,7 @@ skb_pull(skb, 2); else if (is->pppcfg & SC_REJ_COMP_AC) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, 0 /* FREE_READ */ ); + dev_kfree_skb(skb); return; /* discard it silently */ } #ifdef CONFIG_ISDN_MPP @@ -1065,7 +1065,7 @@ net_dev->ib.modify = 0; printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n"); SET_SKB_FREE(skb); - dev_kfree_skb(skb, 0 /* FREE_READ */ ); + dev_kfree_skb(skb); return; /* discard */ } q->skb = skb; @@ -1144,7 +1144,7 @@ printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); net_dev->local.stats.rx_dropped++; SET_SKB_FREE(skb); - dev_kfree_skb(skb, 0 /* FREE_READ */ ); + dev_kfree_skb(skb); return; } #endif @@ -1169,7 +1169,7 @@ if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); net_dev->local.stats.rx_dropped++; - dev_kfree_skb(skb_old, 0 /* FREE_READ */ ); + dev_kfree_skb(skb_old); return; } skb->dev = dev; @@ -1178,10 +1178,10 @@ skb->mac.raw = skb->data; pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_slot]->slcomp, skb->data, skb_old->len); - dev_kfree_skb(skb_old, 0 /* FREE_READ */ ); + dev_kfree_skb(skb_old); if (pkt_len < 0) { SET_SKB_FREE(skb); - dev_kfree_skb(skb, 0 /* FREE_READ */ ); + dev_kfree_skb(skb); lp->stats.rx_dropped++; return; } @@ -1192,14 +1192,14 @@ printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n"); lp->stats.rx_dropped++; SET_SKB_FREE(skb); - dev_kfree_skb(skb, 0 /* FREE_READ */ ); + dev_kfree_skb(skb); return; #endif break; default: isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */ SET_SKB_FREE(skb); - dev_kfree_skb(skb, 0 /* FREE_READ */ ); + dev_kfree_skb(skb); return; } @@ -1273,7 +1273,7 @@ proto = PPP_IPX; /* untested */ break; default: - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocoll: %#x.\n", skb->protocol); return 0; } @@ -1320,10 +1320,10 @@ if (buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*) */ if (new_skb->data != buf) printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n"); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); skb = new_skb; } else { - dev_kfree_skb(new_skb, 0 /* FREE_WRITE */ ); + dev_kfree_skb(new_skb); } skb_trim(skb, pktlen); @@ -1389,7 +1389,7 @@ if (isdn_net_send_skb(dev, lp, skb)) { if (lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */ printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", dev->name); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } else lp->sav_skb = skb; } @@ -1408,7 +1408,7 @@ struct sqqueue *qn = q->next; if (q->skb) { SET_SKB_FREE(q->skb); - dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); + dev_kfree_skb(q->skb); } kfree(q); q = qn; @@ -1425,7 +1425,7 @@ while (q) { struct mpqueue *ql = q->next; SET_SKB_FREE(q->skb); - dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); + dev_kfree_skb(q->skb); kfree(q); q = ql; } @@ -1600,7 +1600,7 @@ while (q) { struct mpqueue *ql = q->next; SET_SKB_FREE(q->skb); - dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); + dev_kfree_skb(q->skb); kfree(q); q = ql; } @@ -1613,7 +1613,7 @@ memcpy((*skb)->data + cnt, q->skb->data, q->skb->len); cnt += q->skb->len; SET_SKB_FREE(q->skb); - dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); + dev_kfree_skb(q->skb); kfree(q); q = ql; } @@ -1672,7 +1672,7 @@ while (q) { ql = q->last; SET_SKB_FREE(q->skb); - dev_kfree_skb(q->skb, 0 /* FREE_READ */ ); + dev_kfree_skb(q->skb); kfree(q); #ifdef CONFIG_ISDN_PPP_VJ toss = 1; diff -ur --new-file old/linux/drivers/isdn/isdn_syms.c new/linux/drivers/isdn/isdn_syms.c --- old/linux/drivers/isdn/isdn_syms.c Thu Feb 27 19:57:30 1997 +++ new/linux/drivers/isdn/isdn_syms.c Sat Feb 21 03:28:22 1998 @@ -21,7 +21,6 @@ * Added GPL-Header, Id and Log * */ -#include #include #include diff -ur --new-file old/linux/drivers/isdn/isdn_tty.c new/linux/drivers/isdn/isdn_tty.c --- old/linux/drivers/isdn/isdn_tty.c Mon Dec 29 19:22:42 1997 +++ new/linux/drivers/isdn/isdn_tty.c Tue Feb 10 22:07:50 1998 @@ -276,7 +276,7 @@ tty->flip.flag_buf_ptr[len - 1] = 0xff; queue_task(&tty->flip.tqueue, &tq_timer); SET_SKB_FREE(skb); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return 1; } } @@ -372,7 +372,7 @@ ) { /* If Modem not listening, drop data */ SET_SKB_FREE(skb); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return 1; } if (info->emu.mdmreg[13] & 2) @@ -384,7 +384,7 @@ printk(KERN_WARNING "isdn_audio: insufficient skb_headroom, dropping\n"); SET_SKB_FREE(skb); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return 1; } ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; @@ -456,13 +456,13 @@ if (skb_queue_len(&info->xmit_queue)) while ((skb = skb_dequeue(&info->xmit_queue))) { SET_SKB_FREE(skb); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); } #ifdef CONFIG_ISDN_AUDIO if (skb_queue_len(&info->dtmf_queue)) while ((skb = skb_dequeue(&info->dtmf_queue))) { SET_SKB_FREE(skb); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); } #endif restore_flags(flags); @@ -493,7 +493,7 @@ if (slen < 0) { /* Error: no channel, already shutdown, or wrong parameter */ SET_SKB_FREE(skb); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return; } if (slen) diff -ur --new-file old/linux/drivers/isdn/pcbit/drv.c new/linux/drivers/isdn/pcbit/drv.c --- old/linux/drivers/isdn/pcbit/drv.c Fri May 30 06:53:06 1997 +++ new/linux/drivers/isdn/pcbit/drv.c Tue Feb 10 22:07:50 1998 @@ -733,7 +733,7 @@ SET_SKB_FREE(skb); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); } diff -ur --new-file old/linux/drivers/isdn/pcbit/layer2.c new/linux/drivers/isdn/pcbit/layer2.c --- old/linux/drivers/isdn/pcbit/layer2.c Thu Feb 27 19:57:30 1997 +++ new/linux/drivers/isdn/pcbit/layer2.c Tue Feb 10 22:07:50 1998 @@ -106,13 +106,13 @@ unsigned long flags; if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return -1; } if ((frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf), GFP_ATOMIC)) == NULL) { printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n"); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return -1; } frame->msg = msg; @@ -287,7 +287,7 @@ if (frame->skb != NULL) { /* free frame */ - dev_kfree_skb(frame->skb, FREE_WRITE); + dev_kfree_skb(frame->skb); } kfree(frame); } @@ -382,7 +382,7 @@ /* discard previous queued frame */ if (dev->read_frame->skb) { SET_SKB_FREE(dev->read_frame->skb); - kfree_skb(dev->read_frame->skb, FREE_READ); + kfree_skb(dev->read_frame->skb); } kfree(dev->read_frame); dev->read_frame = NULL; @@ -650,7 +650,7 @@ if (dev->read_frame) { if (dev->read_frame->skb) { SET_SKB_FREE(dev->read_frame->skb); - kfree_skb(dev->read_frame->skb, FREE_READ); + kfree_skb(dev->read_frame->skb); } kfree(dev->read_frame); dev->read_frame = NULL; @@ -661,7 +661,7 @@ dev->write_queue = dev->write_queue->next; if (frame->skb) { - dev_kfree_skb(frame->skb, FREE_WRITE); + dev_kfree_skb(frame->skb); } kfree(frame); #else diff -ur --new-file old/linux/drivers/isdn/pcbit/module.c new/linux/drivers/isdn/pcbit/module.c --- old/linux/drivers/isdn/pcbit/module.c Thu Feb 27 19:57:30 1997 +++ new/linux/drivers/isdn/pcbit/module.c Sun Jan 25 19:05:46 1998 @@ -22,10 +22,10 @@ #include #include "pcbit.h" -int mem[MAX_PCBIT_CARDS] = {0, }; -int irq[MAX_PCBIT_CARDS] = {0, }; +static int mem[MAX_PCBIT_CARDS] = {0, }; +static int irq[MAX_PCBIT_CARDS] = {0, }; -int num_boards; +static int num_boards; struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, 0, 0, 0}; int init_module(void); diff -ur --new-file old/linux/drivers/isdn/sc/hardware.h new/linux/drivers/isdn/sc/hardware.h --- old/linux/drivers/isdn/sc/hardware.h Thu Feb 27 19:57:30 1997 +++ new/linux/drivers/isdn/sc/hardware.h Sun Jan 25 19:05:46 1998 @@ -16,11 +16,6 @@ this, you must also change the number of elements in io, irq, and ram to match. Initialized in init.c */ -/* -extern unsigned int io[]; -extern unsigned char irq[]; -extern unsigned long ram[]; -*/ #define SIGNATURE 0x87654321 /* Board reset signature */ #define SIG_OFFSET 0x1004 /* Where to find signature in shared RAM */ diff -ur --new-file old/linux/drivers/isdn/sc/includes.h new/linux/drivers/isdn/sc/includes.h --- old/linux/drivers/isdn/sc/includes.h Thu Feb 27 19:57:30 1997 +++ new/linux/drivers/isdn/sc/includes.h Sun Jan 25 19:05:46 1998 @@ -1,6 +1,5 @@ #include #include -#include #include #include #include diff -ur --new-file old/linux/drivers/isdn/sc/init.c new/linux/drivers/isdn/sc/init.c --- old/linux/drivers/isdn/sc/init.c Fri May 30 06:53:06 1997 +++ new/linux/drivers/isdn/sc/init.c Sun Jan 25 19:05:46 1998 @@ -11,10 +11,10 @@ const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" }; /* insmod set parameters */ -unsigned int io[] = {0,0,0,0}; -unsigned char irq[] = {0,0,0,0}; -unsigned long ram[] = {0,0,0,0}; -int do_reset = 0; +static unsigned int io[] = {0,0,0,0}; +static unsigned char irq[] = {0,0,0,0}; +static unsigned long ram[] = {0,0,0,0}; +static int do_reset = 0; static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 }; #define MAX_IRQS 10 diff -ur --new-file old/linux/drivers/isdn/sc/packet.c new/linux/drivers/isdn/sc/packet.c --- old/linux/drivers/isdn/sc/packet.c Thu Feb 27 19:57:30 1997 +++ new/linux/drivers/isdn/sc/packet.c Tue Feb 10 22:07:50 1998 @@ -100,7 +100,7 @@ adapter[card]->channel[channel].num_sendbufs ? 0 : adapter[card]->channel[channel].next_sendbuf; pr_debug("%s: Packet sent successfully\n", adapter[card]->devicename); - dev_kfree_skb(data, FREE_WRITE); + dev_kfree_skb(data); indicate_status(card,ISDN_STAT_BSENT,channel,NULL); } return data->len; diff -ur --new-file old/linux/drivers/macintosh/aty.c new/linux/drivers/macintosh/aty.c --- old/linux/drivers/macintosh/aty.c Tue Jan 13 00:18:13 1998 +++ new/linux/drivers/macintosh/aty.c Wed Feb 25 07:08:01 1998 @@ -11,6 +11,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include /* for CONFIG_CHIP_ID and CONFIG_STAT0 */ #include #include #include @@ -38,11 +39,11 @@ typedef struct aty_regvals { int offset[3]; /* first pixel address */ - int crtc_h_sync_strt_wid[3]; /* depth dependant */ + int crtc_h_sync_strt_wid[3]; /* depth dependent */ int crtc_gen_cntl[3]; int mem_cntl[3]; - int crtc_h_tot_disp; /* mode dependant */ + int crtc_h_tot_disp; /* mode dependent */ int crtc_v_tot_disp; int crtc_v_sync_strt_wid; int crtc_off_pitch; diff -ur --new-file old/linux/drivers/misc/BUGS-parport new/linux/drivers/misc/BUGS-parport --- old/linux/drivers/misc/BUGS-parport Tue Aug 26 23:52:44 1997 +++ new/linux/drivers/misc/BUGS-parport Sat Jan 24 05:04:03 1998 @@ -1,6 +1,4 @@ Currently known (or at least suspected) bugs in parport: -o IEEE1284 code does not do the terminating handshake after transfers, which - seems to upset some devices. - o lp doesn't allow you to read status while printing is in progress. + diff -ur --new-file old/linux/drivers/misc/Makefile new/linux/drivers/misc/Makefile --- old/linux/drivers/misc/Makefile Sun Nov 30 01:19:40 1997 +++ new/linux/drivers/misc/Makefile Sat Jan 24 05:04:03 1998 @@ -48,10 +48,10 @@ M_OBJS += parport.o endif ifeq ($(CONFIG_PARPORT_PC),m) - MX_OBJS += parport_pc.o + M_OBJS += parport_pc.o endif ifeq ($(CONFIG_PARPORT_AX),m) - MX_OBJS += parport_ax.o + M_OBJS += parport_ax.o endif endif diff -ur --new-file old/linux/drivers/misc/TODO-parport new/linux/drivers/misc/TODO-parport --- old/linux/drivers/misc/TODO-parport Sat Sep 20 20:43:22 1997 +++ new/linux/drivers/misc/TODO-parport Sat Jan 24 05:04:03 1998 @@ -4,7 +4,7 @@ 1. Proper documentation. -2. Overhaul lp.c: +2. A better lp.c: a) It's a _mess_ @@ -18,4 +18,8 @@ bits when they have something to say. We should read out and deal with (maybe just log) whatever the printer wants to tell the world. -3. Assimilate more drivers. +3. Support more hardware (eg m68k, Sun bpp). + +4. A better PLIP (make use of bidirectional/ECP/EPP ports). + + diff -ur --new-file old/linux/drivers/misc/parport_arc.c new/linux/drivers/misc/parport_arc.c --- old/linux/drivers/misc/parport_arc.c Tue Aug 26 23:52:44 1997 +++ new/linux/drivers/misc/parport_arc.c Wed Feb 25 07:33:03 1998 @@ -1,37 +1,45 @@ -/* Parallel-port routines for ARC onboard hardware. +/* Low-level parallel port routines for Archimedes onboard hardware * * Author: Phil Blundell */ -#include - -#include -#include -#include +/* This driver is for the parallel port hardware found on Acorn's old + * range of Archimedes machines. The A5000 and newer systems have PC-style + * I/O hardware and should use the parport_pc driver instead. + * + * The Acorn printer port hardware is very simple. There is a single 8-bit + * write-only latch for the data port and control/status bits are handled + * with various auxilliary input and output lines. The port is not + * bidirectional, does not support any modes other than SPP, and has only + * a subset of the standard printer control lines connected. + */ +#include #include #include #include #include #include #include - #include -#include +#include +#include +#include +#include #define DATA_LATCH 0x3350010 /* ARC can't read from the data latch, so we must use a soft copy. */ -static unsigned int data_copy; +static unsigned char data_copy; -static void arc_write_data(struct parport *p, unsigned int data) +static void arc_write_data(struct parport *p, unsigned char data) { data_copy = data; outb(data, DATA_LATCH); } -static unsigned int arc_read_data(struct parport *p) +static unsigned char arc_read_data(struct parport *p) { return data_copy; } @@ -50,7 +58,7 @@ #endif } -static struct parport_operations arc_ops = +static struct parport_operations parport_arc_ops = { arc_write_data, arc_read_data, @@ -90,3 +98,31 @@ arc_inc_use_count, arc_dec_use_count }; + +/* --- Initialisation code -------------------------------- */ + +int parport_arc_init(void) +{ + /* Archimedes hardware provides only one port, at a fixed address */ + struct parport *p; + + if (check_region(DATA_LATCH, 4)) + return 0; + + if (!(p = parport_register_port(base, IRQ_PRINTERACK, + PARPORT_DMA_NONE, &parport_arc_ops))) + return 0; + + p->modes = PARPORT_MODE_ARCSPP; + p->size = 4; + + printk(KERN_INFO "%s: Archimedes on-board port, using irq %d\n", + p->irq); + parport_proc_register(p); + p->flags |= PARPORT_FLAG_COMA; + + if (parport_probe_hook) + (*parport_probe_hook)(p); + + return 1; +} 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 Sat Dec 6 20:58:23 1997 +++ new/linux/drivers/misc/parport_ax.c Wed Feb 25 07:33:03 1998 @@ -1,4 +1,4 @@ -/* $Id: parport_ax.c,v 1.2 1997/10/25 17:27:03 philip Exp $ +/* $Id: parport_ax.c,v 1.5 1998/01/10 18:28:39 ecd Exp $ * Parallel-port routines for Sun Ultra/AX architecture * * Author: Eddie C. Dost @@ -12,12 +12,12 @@ */ #include -#include #include #include #include #include #include +#include #include @@ -36,116 +36,126 @@ #undef HAVE_SLOW_DEVICES -#define DATA 0x00 -#define STATUS 0x01 -#define CONTROL 0x02 - -#define CFIFO 0x400 -#define DFIFO 0x400 -#define TFIFO 0x400 -#define CNFA 0x400 -#define CNFB 0x401 -#define ECR 0x402 +#define DATA 0x00 +#define STATUS 0x01 +#define CONTROL 0x02 +#define EPPREG 0x04 + +#define CFIFO 0x400 +#define DFIFO 0x400 +#define TFIFO 0x400 +#define CONFIGA 0x400 +#define CONFIGB 0x401 +#define ECONTROL 0x402 static void -ax_null_intr_func(int irq, void *dev_id, struct pt_regs *regs) +parport_ax_null_intr_func(int irq, void *dev_id, struct pt_regs *regs) { /* NULL function - Does nothing */ - return; } -#if 0 -static unsigned int -ax_read_configb(struct parport *p) +void +parport_ax_write_epp(struct parport *p, unsigned char d) { - return (unsigned int)inb(p->base + CNFB); + outb(d, p->base + EPPREG); } -#endif -static void -ax_write_data(struct parport *p, unsigned int d) +unsigned char +parport_ax_read_epp(struct parport *p) +{ + return inb(p->base + EPPREG); +} + +unsigned char +parport_ax_read_configb(struct parport *p) +{ + return inb(p->base + CONFIGB); +} + +void +parport_ax_write_data(struct parport *p, unsigned char d) { outb(d, p->base + DATA); } -static unsigned int -ax_read_data(struct parport *p) +unsigned char +parport_ax_read_data(struct parport *p) { - return (unsigned int)inb(p->base + DATA); + return inb(p->base + DATA); } -static void -ax_write_control(struct parport *p, unsigned int d) +void +parport_ax_write_control(struct parport *p, unsigned char d) { outb(d, p->base + CONTROL); } -static unsigned int -ax_read_control(struct parport *p) +unsigned char +parport_ax_read_control(struct parport *p) { - return (unsigned int)inb(p->base + CONTROL); + return inb(p->base + CONTROL); } -static unsigned int -ax_frob_control(struct parport *p, unsigned int mask, unsigned int val) +unsigned char +parport_ax_frob_control(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base + CONTROL); + unsigned char old = inb(p->base + CONTROL); outb(((old & ~mask) ^ val), p->base + CONTROL); return old; } -static void -ax_write_status(struct parport *p, unsigned int d) +void +parport_ax_write_status(struct parport *p, unsigned char d) { outb(d, p->base + STATUS); } -static unsigned int -ax_read_status(struct parport *p) +unsigned char +parport_ax_read_status(struct parport *p) { - return (unsigned int)inb(p->base + STATUS); + return inb(p->base + STATUS); } -static void -ax_write_econtrol(struct parport *p, unsigned int d) +void +parport_ax_write_econtrol(struct parport *p, unsigned char d) { - outb(d, p->base + ECR); + outb(d, p->base + ECONTROL); } -static unsigned int -ax_read_econtrol(struct parport *p) +unsigned char +parport_ax_read_econtrol(struct parport *p) { - return (unsigned int)inb(p->base + ECR); + return inb(p->base + ECONTROL); } -static unsigned int -ax_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val) +unsigned char +parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base + ECR); - outb(((old & ~mask) ^ val), p->base + ECR); + unsigned char old = inb(p->base + ECONTROL); + outb(((old & ~mask) ^ val), p->base + ECONTROL); return old; } -static void -ax_change_mode(struct parport *p, int m) +void +parport_ax_change_mode(struct parport *p, int m) { - ax_frob_econtrol(p, 0xe0, m << 5); + parport_ax_frob_econtrol(p, 0xe0, m << 5); } -static void -ax_write_fifo(struct parport *p, unsigned int v) +void +parport_ax_write_fifo(struct parport *p, unsigned char v) { outb(v, p->base + DFIFO); } -static unsigned int -ax_read_fifo(struct parport *p) +unsigned char +parport_ax_read_fifo(struct parport *p) { return inb(p->base + DFIFO); } -static void -ax_disable_irq(struct parport *p) +void +parport_ax_disable_irq(struct parport *p) { struct linux_ebus_dma *dma = p->private_data; unsigned int dcsr; @@ -155,8 +165,8 @@ writel(dcsr, (unsigned long)&dma->dcsr); } -static void -ax_enable_irq(struct parport *p) +void +parport_ax_enable_irq(struct parport *p) { struct linux_ebus_dma *dma = p->private_data; unsigned int dcsr; @@ -166,11 +176,11 @@ writel(dcsr, (unsigned long)&dma->dcsr); } -static void -ax_release_resources(struct parport *p) +void +parport_ax_release_resources(struct parport *p) { if (p->irq != PARPORT_IRQ_NONE) { - ax_disable_irq(p); + parport_ax_disable_irq(p); free_irq(p->irq, NULL); } release_region(p->base, p->size); @@ -180,13 +190,14 @@ sizeof(struct linux_ebus_dma)); } -static int -ax_claim_resources(struct parport *p) +int +parport_ax_claim_resources(struct parport *p) { /* FIXME check that resources are free */ if (p->irq != PARPORT_IRQ_NONE) { - request_irq(p->irq, ax_null_intr_func, 0, p->name, NULL); - ax_enable_irq(p); + request_irq(p->irq, parport_ax_null_intr_func, + 0, p->name, NULL); + parport_ax_enable_irq(p); } request_region(p->base, p->size, p->name); if (p->modes & PARPORT_MODE_PCECR) @@ -196,109 +207,109 @@ return 0; } -static void -ax_save_state(struct parport *p, struct parport_state *s) +void +parport_ax_save_state(struct parport *p, struct parport_state *s) { - s->u.pc.ctr = ax_read_control(p); - s->u.pc.ecr = ax_read_econtrol(p); + s->u.pc.ctr = parport_ax_read_control(p); + s->u.pc.ecr = parport_ax_read_econtrol(p); } -static void -ax_restore_state(struct parport *p, struct parport_state *s) +void +parport_ax_restore_state(struct parport *p, struct parport_state *s) { - ax_write_control(p, s->u.pc.ctr); - ax_write_econtrol(p, s->u.pc.ecr); + parport_ax_write_control(p, s->u.pc.ctr); + parport_ax_write_econtrol(p, s->u.pc.ecr); } -static unsigned int -ax_epp_read_block(struct parport *p, void *buf, unsigned int length) +size_t +parport_ax_epp_read_block(struct parport *p, void *buf, size_t length) { return 0; /* FIXME */ } -static unsigned int -ax_epp_write_block(struct parport *p, void *buf, unsigned int length) +size_t +parport_ax_epp_write_block(struct parport *p, void *buf, size_t length) { return 0; /* FIXME */ } -static unsigned int -ax_ecp_read_block(struct parport *p, void *buf, unsigned int length, - void (*fn)(struct parport *, void *, unsigned int), - void *handle) +int +parport_ax_ecp_read_block(struct parport *p, void *buf, size_t length, + void (*fn)(struct parport *, void *, size_t), + void *handle) { return 0; /* FIXME */ } -static unsigned int -ax_ecp_write_block(struct parport *p, void *buf, unsigned int length, - void (*fn)(struct parport *, void *, unsigned int), - void *handle) +int +parport_ax_ecp_write_block(struct parport *p, void *buf, size_t length, + void (*fn)(struct parport *, void *, size_t), + void *handle) { return 0; /* FIXME */ } -static int -ax_examine_irq(struct parport *p) +int +parport_ax_examine_irq(struct parport *p) { return 0; /* FIXME */ } -static void -ax_inc_use_count(void) +void +parport_ax_inc_use_count(void) { #ifdef MODULE MOD_INC_USE_COUNT; #endif } -static void -ax_dec_use_count(void) +void +parport_ax_dec_use_count(void) { #ifdef MODULE MOD_DEC_USE_COUNT; #endif } -static struct parport_operations ax_ops = +static struct parport_operations parport_ax_ops = { - ax_write_data, - ax_read_data, + parport_ax_write_data, + parport_ax_read_data, - ax_write_control, - ax_read_control, - ax_frob_control, + parport_ax_write_control, + parport_ax_read_control, + parport_ax_frob_control, - ax_write_econtrol, - ax_read_econtrol, - ax_frob_econtrol, + parport_ax_write_econtrol, + parport_ax_read_econtrol, + parport_ax_frob_econtrol, - ax_write_status, - ax_read_status, + parport_ax_write_status, + parport_ax_read_status, - ax_write_fifo, - ax_read_fifo, + parport_ax_write_fifo, + parport_ax_read_fifo, - ax_change_mode, + parport_ax_change_mode, - ax_release_resources, - ax_claim_resources, + parport_ax_release_resources, + parport_ax_claim_resources, - ax_epp_write_block, - ax_epp_read_block, + parport_ax_epp_write_block, + parport_ax_epp_read_block, - ax_ecp_write_block, - ax_ecp_read_block, + parport_ax_ecp_write_block, + parport_ax_ecp_read_block, - ax_save_state, - ax_restore_state, + parport_ax_save_state, + parport_ax_restore_state, - ax_enable_irq, - ax_disable_irq, - ax_examine_irq, + parport_ax_enable_irq, + parport_ax_disable_irq, + parport_ax_examine_irq, - ax_inc_use_count, - ax_dec_use_count + parport_ax_inc_use_count, + parport_ax_dec_use_count }; @@ -308,19 +319,20 @@ /* Check for ECP * - * Old style XT ports alias io ports every 0x400, hence accessing ECR + * Old style XT ports alias io ports every 0x400, hence accessing ECONTROL * on these cards actually accesses the CTR. * - * Modern cards don't do this but reading from ECR will return 0xff + * Modern cards don't do this but reading from ECONTROL will return 0xff * regardless of what is written here if the card does NOT support * ECP. * - * We will write 0x2c to ECR and 0xcc to CTR since both of these + * We will write 0x2c to ECONTROL and 0xcc to CTR since both of these * values are "safe" on the CTR since bits 6-7 of CTR are unused. */ static int parport_ECR_present(struct parport *pb) { - unsigned int r, octr = pb->ops->read_control(pb), + unsigned int r; + unsigned char octr = pb->ops->read_control(pb), oecr = pb->ops->read_econtrol(pb); r = pb->ops->read_control(pb); @@ -330,7 +342,7 @@ r = pb->ops->read_control(pb); if ((pb->ops->read_econtrol(pb) & 0x2) == (r & 0x2)) { pb->ops->write_control(pb, octr); - return 0; /* Sure that no ECR register exists */ + return 0; /* Sure that no ECONTROL register exists */ } } @@ -349,14 +361,15 @@ static int parport_ECP_supported(struct parport *pb) { - int i, oecr = pb->ops->read_econtrol(pb); + int i; + unsigned char oecr = pb->ops->read_econtrol(pb); - /* If there is no ECR, we have no hope of supporting ECP. */ + /* If there is no ECONTROL, we have no hope of supporting ECP. */ if (!(pb->modes & PARPORT_MODE_PCECR)) return 0; /* - * Using LGS chipset it uses ECR register, but + * Using LGS chipset it uses ECONTROL register, but * it doesn't support ECP or FIFO MODE */ @@ -387,7 +400,8 @@ static int parport_PS2_supported(struct parport *pb) { - int ok = 0, octr = pb->ops->read_control(pb); + int ok = 0; + unsigned char octr = pb->ops->read_control(pb); pb->ops->write_control(pb, octr | 0x20); /* try to tri-state buffer */ @@ -404,7 +418,8 @@ static int parport_ECPPS2_supported(struct parport *pb) { - int mode, oecr = pb->ops->read_econtrol(pb); + int mode; + unsigned char oecr = pb->ops->read_econtrol(pb); if (!(pb->modes & PARPORT_MODE_PCECR)) return 0; @@ -439,7 +454,7 @@ /* Setup temporary access to Device operations */ tmpport.base = dev->base_address[0]; - tmpport.ops = &ax_ops; + tmpport.ops = &parport_ax_ops; /* Enable ECP mode, set bit 2 of the CTR first */ tmpport.ops->write_control(&tmpport, 0x04); @@ -472,7 +487,7 @@ irq = dev->irqs[0]; dma = PARPORT_DMA_AUTO; - if (!(p = parport_register_port(base, irq, dma, &ax_ops))) + if (!(p = parport_register_port(base, irq, dma, &parport_ax_ops))) return 0; /* Safe away pointer to our EBus DMA */ @@ -506,8 +521,8 @@ parport_proc_register(p); p->flags |= PARPORT_FLAG_COMA; - ax_write_control(p, 0x0c); - ax_write_data(p, 0); + p->ops->write_control(p, 0x0c); + p->ops->write_data(p, 0); if (parport_probe_hook) (*parport_probe_hook)(p); @@ -515,8 +530,13 @@ return 1; } -int -parport_ax_init(void) +EXPORT_NO_SYMBOLS; + +#ifdef MODULE +int init_module(void) +#else +__initfunc(int parport_ax_init(void)) +#endif { struct linux_ebus *ebus; struct linux_ebus_device *edev; @@ -525,17 +545,10 @@ for_all_ebusdev(edev, ebus) if (!strcmp(edev->prom_name, "ecpp")) count += init_one_port(edev); - return count; + return count ? 0 : -ENODEV; } #ifdef MODULE - -int -init_module(void) -{ - return (parport_ax_init() ? 0 : 1); -} - void cleanup_module(void) { 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 Nov 30 01:19:41 1997 +++ new/linux/drivers/misc/parport_init.c Tue Mar 10 23:43:13 1998 @@ -1,6 +1,6 @@ /* Parallel-port initialisation code. * - * Authors: David Campbell + * Authors: David Campbell * Tim Waugh * Jose Renau * @@ -17,7 +17,6 @@ #include #include #include -#include #ifndef MODULE static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 }; @@ -57,7 +56,7 @@ #ifdef MODULE int init_module(void) { - parport_proc_init(); + (void)parport_proc_init(); /* We can go on without it. */ return 0; } @@ -68,8 +67,6 @@ #else __initfunc(int parport_init(void)) { - struct parport *pb; - if (io[0] == PARPORT_DISABLE) return 1; @@ -90,6 +87,7 @@ /* Exported symbols for modules. */ EXPORT_SYMBOL(parport_claim); +EXPORT_SYMBOL(parport_claim_or_block); EXPORT_SYMBOL(parport_release); EXPORT_SYMBOL(parport_register_port); EXPORT_SYMBOL(parport_unregister_port); 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 Sat Dec 6 20:58:23 1997 +++ new/linux/drivers/misc/parport_pc.c Wed Feb 25 07:33:03 1998 @@ -1,4 +1,4 @@ -/* Parallel-port routines for PC architecture +/* Low-level parallel-port routines for PC-style hardware. * * Authors: Phil Blundell * Tim Waugh @@ -8,6 +8,29 @@ * based on work by Grant Guenther and Phil Blundell. */ +/* This driver should work with any hardware that is broadly compatible + * with that in the IBM PC. This applies to the majority of integrated + * I/O chipsets that are commonly available. The expected register + * layout is: + * + * base+0 data + * base+1 status + * base+2 control + * + * In addition, there are some optional registers: + * + * base+3 EPP command + * base+4 EPP + * base+0x400 ECP config A + * base+0x401 ECP config B + * base+0x402 ECP control + * + * All registers are 8 bits wide and read/write. If your hardware differs + * only in register addresses (eg because your registers are on 32-bit + * word boundaries) then you can alter the constants in parport_pc.h to + * accomodate this. + */ + #include #include @@ -16,7 +39,6 @@ #include #include -#include #include #include #include @@ -25,120 +47,112 @@ #include #include +#include -#define ECONTROL 0x402 -#define CONFIGB 0x401 -#define CONFIGA 0x400 -#define EPPREG 0x4 -#define CONTROL 0x2 -#define STATUS 0x1 -#define DATA 0 - -#define PC_MAX_PORTS 8 +/* Maximum number of ports to support. It is useless to set this greater + than PARPORT_MAX (in ). */ +#define PARPORT_PC_MAX_PORTS 8 -static void pc_null_intr_func(int irq, void *dev_id, struct pt_regs *regs) +static void parport_pc_null_intr_func(int irq, void *dev_id, struct pt_regs *regs) { - /* NULL function - Does nothing */ - return; + /* Null function - does nothing */ } -#if 0 -static void pc_write_epp(struct parport *p, unsigned int d) +void parport_pc_write_epp(struct parport *p, unsigned char d) { outb(d, p->base+EPPREG); } -#endif -static unsigned int pc_read_epp(struct parport *p) +unsigned char parport_pc_read_epp(struct parport *p) { - return (unsigned int)inb(p->base+EPPREG); + return inb(p->base+EPPREG); } -static unsigned int pc_read_configb(struct parport *p) +unsigned char parport_pc_read_configb(struct parport *p) { - return (unsigned int)inb(p->base+CONFIGB); + return inb(p->base+CONFIGB); } -static void pc_write_data(struct parport *p, unsigned int d) +void parport_pc_write_data(struct parport *p, unsigned char d) { outb(d, p->base+DATA); } -static unsigned int pc_read_data(struct parport *p) +unsigned char parport_pc_read_data(struct parport *p) { - return (unsigned int)inb(p->base+DATA); + return inb(p->base+DATA); } -static void pc_write_control(struct parport *p, unsigned int d) +void parport_pc_write_control(struct parport *p, unsigned char d) { outb(d, p->base+CONTROL); } -static unsigned int pc_read_control(struct parport *p) +unsigned char parport_pc_read_control(struct parport *p) { - return (unsigned int)inb(p->base+CONTROL); + return inb(p->base+CONTROL); } -static unsigned int pc_frob_control(struct parport *p, unsigned int mask, unsigned int val) +unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base+CONTROL); + unsigned char old = inb(p->base+CONTROL); outb(((old & ~mask) ^ val), p->base+CONTROL); return old; } -static void pc_write_status(struct parport *p, unsigned int d) +void parport_pc_write_status(struct parport *p, unsigned char d) { outb(d, p->base+STATUS); } -static unsigned int pc_read_status(struct parport *p) +unsigned char parport_pc_read_status(struct parport *p) { - return (unsigned int)inb(p->base+STATUS); + return inb(p->base+STATUS); } -static void pc_write_econtrol(struct parport *p, unsigned int d) +void parport_pc_write_econtrol(struct parport *p, unsigned char d) { outb(d, p->base+ECONTROL); } -static unsigned int pc_read_econtrol(struct parport *p) +unsigned char parport_pc_read_econtrol(struct parport *p) { - return (unsigned int)inb(p->base+ECONTROL); + return inb(p->base+ECONTROL); } -static unsigned int pc_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val) +unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val) { - unsigned int old = (unsigned int)inb(p->base+ECONTROL); + unsigned char old = inb(p->base+ECONTROL); outb(((old & ~mask) ^ val), p->base+ECONTROL); return old; } -static void pc_change_mode(struct parport *p, int m) +void parport_pc_change_mode(struct parport *p, int m) { /* FIXME */ } -static void pc_write_fifo(struct parport *p, unsigned int v) +void parport_pc_write_fifo(struct parport *p, unsigned char v) { /* FIXME */ } -static unsigned int pc_read_fifo(struct parport *p) +unsigned char parport_pc_read_fifo(struct parport *p) { return 0; /* FIXME */ } -static void pc_disable_irq(struct parport *p) +void parport_pc_disable_irq(struct parport *p) { - /* FIXME */ + parport_pc_frob_control(p, 0x10, 0); } -static void pc_enable_irq(struct parport *p) +void parport_pc_enable_irq(struct parport *p) { - /* FIXME */ + parport_pc_frob_control(p, 0x10, 0x10); } -static void pc_release_resources(struct parport *p) +void parport_pc_release_resources(struct parport *p) { if (p->irq != PARPORT_IRQ_NONE) free_irq(p->irq, NULL); @@ -147,112 +161,110 @@ release_region(p->base+0x400, 3); } -static int pc_claim_resources(struct parport *p) +int parport_pc_claim_resources(struct parport *p) { /* FIXME check that resources are free */ if (p->irq != PARPORT_IRQ_NONE) - request_irq(p->irq, pc_null_intr_func, 0, p->name, NULL); + request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, NULL); request_region(p->base, p->size, p->name); if (p->modes & PARPORT_MODE_PCECR) request_region(p->base+0x400, 3, p->name); return 0; } -static void pc_save_state(struct parport *p, struct parport_state *s) +void parport_pc_save_state(struct parport *p, struct parport_state *s) { - s->u.pc.ctr = pc_read_control(p); - s->u.pc.ecr = pc_read_econtrol(p); + s->u.pc.ctr = parport_pc_read_control(p); + s->u.pc.ecr = parport_pc_read_econtrol(p); } -static void pc_restore_state(struct parport *p, struct parport_state *s) +void parport_pc_restore_state(struct parport *p, struct parport_state *s) { - pc_write_control(p, s->u.pc.ctr); - pc_write_econtrol(p, s->u.pc.ecr); + parport_pc_write_control(p, s->u.pc.ctr); + parport_pc_write_econtrol(p, s->u.pc.ecr); } -static unsigned int pc_epp_read_block(struct parport *p, void *buf, unsigned int length) +size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length) { return 0; /* FIXME */ } -static unsigned int pc_epp_write_block(struct parport *p, void *buf, unsigned int length) +size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length) { return 0; /* FIXME */ } -static unsigned int pc_ecp_read_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle) +int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle) { return 0; /* FIXME */ } -static unsigned int pc_ecp_write_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle) +int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle) { return 0; /* FIXME */ } -static int pc_examine_irq(struct parport *p) +int parport_pc_examine_irq(struct parport *p) { return 0; /* FIXME */ } -static void pc_inc_use_count(void) +void parport_pc_inc_use_count(void) { #ifdef MODULE MOD_INC_USE_COUNT; #endif } -static void pc_dec_use_count(void) +void parport_pc_dec_use_count(void) { #ifdef MODULE MOD_DEC_USE_COUNT; #endif } -static struct parport_operations pc_ops = +struct parport_operations parport_pc_ops = { - pc_write_data, - pc_read_data, + parport_pc_write_data, + parport_pc_read_data, - pc_write_control, - pc_read_control, - pc_frob_control, + parport_pc_write_control, + parport_pc_read_control, + parport_pc_frob_control, - pc_write_econtrol, - pc_read_econtrol, - pc_frob_econtrol, + parport_pc_write_econtrol, + parport_pc_read_econtrol, + parport_pc_frob_econtrol, - pc_write_status, - pc_read_status, + parport_pc_write_status, + parport_pc_read_status, - pc_write_fifo, - pc_read_fifo, + parport_pc_write_fifo, + parport_pc_read_fifo, - pc_change_mode, + parport_pc_change_mode, - pc_release_resources, - pc_claim_resources, + parport_pc_release_resources, + parport_pc_claim_resources, - pc_epp_write_block, - pc_epp_read_block, + parport_pc_epp_write_block, + parport_pc_epp_read_block, - pc_ecp_write_block, - pc_ecp_read_block, + parport_pc_ecp_write_block, + parport_pc_ecp_read_block, - pc_save_state, - pc_restore_state, + parport_pc_save_state, + parport_pc_restore_state, - pc_enable_irq, - pc_disable_irq, - pc_examine_irq, + parport_pc_enable_irq, + parport_pc_disable_irq, + parport_pc_examine_irq, - pc_inc_use_count, - pc_dec_use_count + parport_pc_inc_use_count, + parport_pc_dec_use_count }; -/****************************************************** - * DMA detection section: - */ +/* --- DMA detection -------------------------------------- */ /* * Prepare DMA channels from 0-8 to transmit towards buffer @@ -289,10 +301,10 @@ for (i = 0; i < 8; i++) if (dma & (1 << i)) { - cli(); - enable_dma(i); - sti(); - } + cli(); + enable_dma(i); + sti(); + } return dma; } @@ -325,13 +337,13 @@ /* Only if supports ECP mode */ static int programmable_dma_support(struct parport *pb) { - int dma, oldstate = pc_read_econtrol(pb); + unsigned char dma, oldstate = parport_pc_read_econtrol(pb); - pc_write_econtrol(pb, 0xe0); /* Configuration MODE */ + parport_pc_write_econtrol(pb, 0xe0); /* Configuration MODE */ - dma = pc_read_configb(pb) & 0x07; + dma = parport_pc_read_configb(pb) & 0x07; - pc_write_econtrol(pb, oldstate); + parport_pc_write_econtrol(pb, oldstate); if (dma == 0 || dma == 4) /* Jumper selection */ return PARPORT_DMA_NONE; @@ -363,7 +375,7 @@ static int parport_dma_probe(struct parport *pb) { int dma,retv; - int dsr,dsr_read; + unsigned char dsr,dsr_read; char *buff; retv = programmable_dma_support(pb); @@ -405,26 +417,24 @@ return retv; } -/****************************************************** - * MODE detection section: - */ +/* --- Mode detection ------------------------------------- */ /* * Clear TIMEOUT BIT in EPP MODE */ static int epp_clear_timeout(struct parport *pb) { - int r; + unsigned char r; - if (!(pc_read_status(pb) & 0x01)) + if (!(parport_pc_read_status(pb) & 0x01)) return 1; /* To clear timeout some chips require double read */ - pc_read_status(pb); - r = pc_read_status(pb); - pc_write_status(pb, r | 0x01); /* Some reset by writing 1 */ - pc_write_status(pb, r & 0xfe); /* Others by writing 0 */ - r = pc_read_status(pb); + parport_pc_read_status(pb); + r = parport_pc_read_status(pb); + parport_pc_write_status(pb, r | 0x01); /* Some reset by writing 1 */ + parport_pc_write_status(pb, r & 0xfe); /* Others by writing 0 */ + r = parport_pc_read_status(pb); return !(r & 0x01); } @@ -436,12 +446,12 @@ static int parport_SPP_supported(struct parport *pb) { /* Do a simple read-write test to make sure the port exists. */ - pc_write_control(pb, 0xc); - pc_write_data(pb, 0xaa); - if (pc_read_data(pb) != 0xaa) return 0; + parport_pc_write_control(pb, 0xc); + parport_pc_write_data(pb, 0xaa); + if (parport_pc_read_data(pb) != 0xaa) return 0; - pc_write_data(pb, 0x55); - if (pc_read_data(pb) != 0x55) return 0; + parport_pc_write_data(pb, 0x55); + if (parport_pc_read_data(pb) != 0x55) return 0; return PARPORT_MODE_PCSPP; } @@ -460,36 +470,37 @@ */ static int parport_ECR_present(struct parport *pb) { - unsigned int r, octr = pc_read_control(pb), - oecr = pc_read_econtrol(pb); + unsigned char r, octr = parport_pc_read_control(pb), + oecr = parport_pc_read_econtrol(pb); - r = pc_read_control(pb); - if ((pc_read_econtrol(pb) & 0x3) == (r & 0x3)) { - pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */ - - r = pc_read_control(pb); - if ((pc_read_econtrol(pb) & 0x2) == (r & 0x2)) { - pc_write_control(pb, octr); + 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 ((pc_read_econtrol(pb) & 0x3 ) != 0x1) + if ((parport_pc_read_econtrol(pb) & 0x3 ) != 0x1) return 0; - pc_write_econtrol(pb, 0x34); - if (pc_read_econtrol(pb) != 0x35) + parport_pc_write_econtrol(pb, 0x34); + if (parport_pc_read_econtrol(pb) != 0x35) return 0; - pc_write_econtrol(pb, oecr); - pc_write_control(pb, octr); + parport_pc_write_econtrol(pb, oecr); + parport_pc_write_control(pb, octr); return PARPORT_MODE_PCECR; } static int parport_ECP_supported(struct parport *pb) { - int i, oecr = pc_read_econtrol(pb); + int i; + unsigned char oecr = parport_pc_read_econtrol(pb); /* If there is no ECR, we have no hope of supporting ECP. */ if (!(pb->modes & PARPORT_MODE_PCECR)) @@ -500,11 +511,11 @@ * it doesn't support ECP or FIFO MODE */ - pc_write_econtrol(pb, 0xc0); /* TEST FIFO */ - for (i=0; i < 1024 && (pc_read_econtrol(pb) & 0x01); i++) - pc_write_fifo(pb, 0xaa); + parport_pc_write_econtrol(pb, 0xc0); /* TEST FIFO */ + for (i=0; i < 1024 && (parport_pc_read_econtrol(pb) & 0x01); i++) + parport_pc_write_fifo(pb, 0xaa); - pc_write_econtrol(pb, oecr); + parport_pc_write_econtrol(pb, oecr); return (i==1024)?0:PARPORT_MODE_PCECP; } @@ -526,14 +537,14 @@ if (!epp_clear_timeout(pb)) return 0; /* No way to clear timeout */ - pc_write_control(pb, pc_read_control(pb) | 0x20); - pc_write_control(pb, pc_read_control(pb) | 0x10); + parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20); + parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10); epp_clear_timeout(pb); - pc_read_epp(pb); + parport_pc_read_epp(pb); udelay(30); /* Wait for possible EPP timeout */ - if (pc_read_status(pb) & 0x01) { + if (parport_pc_read_status(pb) & 0x01) { epp_clear_timeout(pb); return PARPORT_MODE_PCEPP; } @@ -543,17 +554,18 @@ static int parport_ECPEPP_supported(struct parport *pb) { - int mode, oecr = pc_read_econtrol(pb); + int mode; + unsigned char oecr = parport_pc_read_econtrol(pb); if (!(pb->modes & PARPORT_MODE_PCECR)) return 0; /* Search for SMC style EPP+ECP mode */ - pc_write_econtrol(pb, 0x80); + parport_pc_write_econtrol(pb, 0x80); mode = parport_EPP_supported(pb); - pc_write_econtrol(pb, oecr); + parport_pc_write_econtrol(pb, oecr); return mode?PARPORT_MODE_PCECPEPP:0; } @@ -577,42 +589,43 @@ static int parport_PS2_supported(struct parport *pb) { - int ok = 0, octr = pc_read_control(pb); + int ok = 0; + unsigned char octr = parport_pc_read_control(pb); epp_clear_timeout(pb); - pc_write_control(pb, octr | 0x20); /* try to tri-state the buffer */ + parport_pc_write_control(pb, octr | 0x20); /* try to tri-state the buffer */ - pc_write_data(pb, 0x55); - if (pc_read_data(pb) != 0x55) ok++; + parport_pc_write_data(pb, 0x55); + if (parport_pc_read_data(pb) != 0x55) ok++; - pc_write_data(pb, 0xaa); - if (pc_read_data(pb) != 0xaa) ok++; + parport_pc_write_data(pb, 0xaa); + if (parport_pc_read_data(pb) != 0xaa) ok++; - pc_write_control(pb, octr); /* cancel input mode */ + parport_pc_write_control(pb, octr); /* cancel input mode */ return ok?PARPORT_MODE_PCPS2:0; } static int parport_ECPPS2_supported(struct parport *pb) { - int mode, oecr = pc_read_econtrol(pb); + int mode; + unsigned char oecr = parport_pc_read_econtrol(pb); if (!(pb->modes & PARPORT_MODE_PCECR)) return 0; - pc_write_econtrol(pb, 0x20); + parport_pc_write_econtrol(pb, 0x20); mode = parport_PS2_supported(pb); - pc_write_econtrol(pb, oecr); + parport_pc_write_econtrol(pb, oecr); return mode?PARPORT_MODE_PCECPPS2:0; } -/****************************************************** - * IRQ detection section: - * - * This code is for detecting ECP interrupts (due to problems with the +/* --- IRQ detection -------------------------------------- */ + +/* This code is for detecting ECP interrupts (due to problems with the * monolithic interrupt probing routines). * * In short this is a voting system where the interrupt with the most @@ -667,46 +680,38 @@ /* Only if supports ECP mode */ static int programmable_irq_support(struct parport *pb) { - int irq, oecr = pc_read_econtrol(pb); + int irq, intrLine; + unsigned char oecr = parport_pc_read_econtrol(pb); + static const int lookup[8] = { + PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 + }; - pc_write_econtrol(pb,0xE0); /* Configuration MODE */ + parport_pc_write_econtrol(pb,0xE0); /* Configuration MODE */ - irq = (pc_read_configb(pb) >> 3) & 0x07; + intrLine = (parport_pc_read_configb(pb) >> 3) & 0x07; + irq = lookup[intrLine]; - switch(irq){ - case 2: - irq = 9; - break; - case 7: - irq = 5; - break; - case 0: - irq = PARPORT_IRQ_NONE; - break; - default: - irq += 7; - } - - pc_write_econtrol(pb, oecr); + parport_pc_write_econtrol(pb, oecr); return irq; } static int irq_probe_ECP(struct parport *pb) { - int irqs, i, oecr = pc_read_econtrol(pb); + int irqs, i; + unsigned char oecr = parport_pc_read_econtrol(pb); probe_irq_off(probe_irq_on()); /* Clear any interrupts */ irqs = open_intr_election(); - pc_write_econtrol(pb, 0x00); /* Reset FIFO */ - pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */ + parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */ + parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */ /* If Full FIFO sure that WriteIntrThresold is generated */ - for (i=0; i < 1024 && !(pc_read_econtrol(pb) & 0x02) ; i++) - pc_write_fifo(pb, 0xaa); + for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++) + parport_pc_write_fifo(pb, 0xaa); pb->irq = close_intr_election(irqs); - pc_write_econtrol(pb, oecr); + parport_pc_write_econtrol(pb, oecr); return pb->irq; } @@ -716,7 +721,8 @@ */ static int irq_probe_EPP(struct parport *pb) { - int irqs, octr = pc_read_control(pb); + int irqs; + unsigned char octr = parport_pc_read_control(pb); #ifndef ADVANCED_DETECT return PARPORT_IRQ_NONE; @@ -726,27 +732,28 @@ irqs = open_intr_election(); if (pb->modes & PARPORT_MODE_PCECR) - pc_write_econtrol(pb, pc_read_econtrol(pb) | 0x10); + parport_pc_write_econtrol(pb, parport_pc_read_econtrol(pb) | 0x10); epp_clear_timeout(pb); - pc_write_control(pb, pc_read_control(pb) | 0x20); - pc_write_control(pb, pc_read_control(pb) | 0x10); + parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20); + parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10); epp_clear_timeout(pb); /* Device isn't expecting an EPP read * and generates an IRQ. */ - pc_read_epp(pb); + parport_pc_read_epp(pb); udelay(20); pb->irq = close_intr_election(irqs); - pc_write_control(pb, octr); + parport_pc_write_control(pb, octr); return pb->irq; } static int irq_probe_SPP(struct parport *pb) { - int irqs, octr = pc_read_control(pb); + int irqs; + unsigned char octr = parport_pc_read_control(pb); #ifndef ADVANCED_DETECT return PARPORT_IRQ_NONE; @@ -756,26 +763,26 @@ irqs = probe_irq_on(); if (pb->modes & PARPORT_MODE_PCECR) - pc_write_econtrol(pb, 0x10); + parport_pc_write_econtrol(pb, 0x10); - pc_write_data(pb,0x00); - pc_write_control(pb,0x00); - pc_write_control(pb,0x0c); + parport_pc_write_data(pb,0x00); + parport_pc_write_control(pb,0x00); + parport_pc_write_control(pb,0x0c); udelay(5); - pc_write_control(pb,0x0d); + parport_pc_write_control(pb,0x0d); udelay(5); - pc_write_control(pb,0x0c); + parport_pc_write_control(pb,0x0c); udelay(25); - pc_write_control(pb,0x08); + parport_pc_write_control(pb,0x08); udelay(25); - pc_write_control(pb,0x0c); + parport_pc_write_control(pb,0x0c); udelay(50); pb->irq = probe_irq_off(irqs); if (pb->irq <= 0) pb->irq = PARPORT_IRQ_NONE; /* No interrupt detected */ - pc_write_control(pb, octr); + parport_pc_write_control(pb, octr); return pb->irq; } @@ -796,10 +803,10 @@ if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_PCECPEPP)) { - int oecr = pc_read_econtrol(pb); - pc_write_econtrol(pb, 0x80); + int oecr = parport_pc_read_econtrol(pb); + parport_pc_write_econtrol(pb, 0x80); pb->irq = irq_probe_EPP(pb); - pc_write_econtrol(pb, oecr); + parport_pc_write_econtrol(pb, oecr); } epp_clear_timeout(pb); @@ -815,14 +822,16 @@ return pb->irq; } +/* --- Initialisation code -------------------------------- */ + static int probe_one_port(unsigned long int base, int irq, int dma) { struct parport tmpport, *p; if (check_region(base, 3)) return 0; tmpport.base = base; - tmpport.ops = &pc_ops; + tmpport.ops = &parport_pc_ops; if (!(parport_SPP_supported(&tmpport))) return 0; - if (!(p = parport_register_port(base, irq, dma, &pc_ops))) 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->base != 0x3bc) { if (!check_region(base+0x400,3)) { @@ -866,8 +875,8 @@ p->flags |= PARPORT_FLAG_COMA; /* Done probing. Now put the port into a sensible start-up state. */ - pc_write_control(p, 0xc); - pc_write_data(p, 0); + parport_pc_write_control(p, 0xc); + parport_pc_write_data(p, 0); if (parport_probe_hook) (*parport_probe_hook)(p); @@ -882,23 +891,29 @@ /* Only probe the ports we were given. */ do { count += probe_one_port(*(io++), *(irq++), *(dma++)); - } while (*io && (++i < PC_MAX_PORTS)); + } while (*io && (++i < PARPORT_PC_MAX_PORTS)); } else { /* Probe all the likely ports. */ count += probe_one_port(0x3bc, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO); count += probe_one_port(0x378, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO); count += probe_one_port(0x278, PARPORT_IRQ_AUTO, PARPORT_DMA_AUTO); } + + /* Give any attached devices a chance to gather their thoughts */ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 75; + schedule (); + return count; } #ifdef MODULE -static int io[PC_MAX_PORTS+1] = { [0 ... PC_MAX_PORTS] = 0 }; -static int dma[PC_MAX_PORTS] = { [0 ... PC_MAX_PORTS-1] = PARPORT_DMA_AUTO }; -static int irq[PC_MAX_PORTS] = { [0 ... PC_MAX_PORTS-1] = PARPORT_IRQ_AUTO }; -MODULE_PARM(io, "1-" __MODULE_STRING(PC_MAX_PORTS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(PC_MAX_PORTS) "i"); -MODULE_PARM(dma, "1-" __MODULE_STRING(PC_MAX_PORTS) "i"); +static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 }; +static int dma[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO }; +static int irq[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_AUTO }; +MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); +MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i"); int init_module(void) { diff -ur --new-file old/linux/drivers/misc/parport_procfs.c new/linux/drivers/misc/parport_procfs.c --- old/linux/drivers/misc/parport_procfs.c Sun Nov 30 01:19:41 1997 +++ new/linux/drivers/misc/parport_procfs.c Fri Feb 13 01:46:29 1998 @@ -1,10 +1,12 @@ /* Parallel port /proc interface code. * - * Authors: David Campbell - * Tim Waugh + * Authors: David Campbell + * Tim Waugh + * Philip Blundell + * Andrea Arcangeli * * based on work by Grant Guenther - * and Philip Blundell + * and Philip Blundell */ #include @@ -12,6 +14,7 @@ #include #include #include +#include #include #include @@ -19,61 +22,64 @@ #include #include #include - #include - #include -#undef PARPORT_INCLUDE_BENCH - -struct proc_dir_entry *base=NULL; +struct proc_dir_entry *base = NULL; extern void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs); static int irq_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) { - int newirq; + int newirq, oldirq; struct parport *pp = (struct parport *)data; - if (count > 4 ) /* more than 4 digits for a irq 0x?? 0?? ?? */ - return(-EOVERFLOW); + if (count > 5 ) /* more than 4 digits + \n for a irq 0x?? 0?? ?? */ + return -EOVERFLOW; if (buffer[0] < 32 || !strncmp(buffer, "none", 4)) { newirq = PARPORT_IRQ_NONE; } else { if (buffer[0] == '0') { - if( buffer[1] == 'x' ) - newirq = simple_strtoul(&buffer[2],0,16); + if (buffer[1] == 'x') + newirq = simple_strtoul(&buffer[2], 0, 16); else - newirq = simple_strtoul(&buffer[1],0,8); + newirq = simple_strtoul(&buffer[1], 0, 8); } else { - newirq = simple_strtoul(buffer,0,10); + newirq = simple_strtoul(buffer, 0, 10); } } - if (pp->irq != PARPORT_IRQ_NONE && !(pp->flags & PARPORT_FLAG_COMA)) - free_irq(pp->irq, pp); + if (newirq >= NR_IRQS) + return -EOVERFLOW; + if (pp->irq != PARPORT_IRQ_NONE && !(pp->flags & PARPORT_FLAG_COMA)) { + if (pp->cad != NULL && pp->cad->irq_func != NULL) + free_irq(pp->irq, pp->cad->private); + else + free_irq(pp->irq, NULL); + } + + oldirq = pp->irq; pp->irq = newirq; if (pp->irq != PARPORT_IRQ_NONE && !(pp->flags & PARPORT_FLAG_COMA)) { - struct pardevice *pd = pp->cad; + struct pardevice *cad = pp->cad; - if (pd == NULL) { - pd = pp->devices; - if (pd != NULL) - request_irq(pp->irq, pd->irq_func ? - pd->irq_func : - parport_null_intr_func, - SA_INTERRUPT, pd->name, pd->port); - } else { - request_irq(pp->irq, pd->irq_func ? pd->irq_func : - parport_null_intr_func, - SA_INTERRUPT, pp->name, pd->port); - } + if (cad == NULL) + request_irq(pp->irq, parport_null_intr_func, + SA_INTERRUPT, pp->name, NULL); + else + request_irq(pp->irq, cad->irq_func ? cad->irq_func : + parport_null_intr_func, SA_INTERRUPT, + cad->name, cad->private); } + if (oldirq != PARPORT_IRQ_NONE && newirq == PARPORT_IRQ_NONE && + pp->cad != NULL && pp->cad->irq_func != NULL) + pp->cad->irq_func(pp->irq, pp->cad->private, NULL); + return count; } @@ -102,16 +108,13 @@ for (pd1 = pp->devices; pd1 ; pd1 = pd1->next) { if (pd1 == pp->cad) - len += sprintf(page+len, "+"); + page[len++] = '+'; else - len += sprintf(page+len, " "); + page[len++] = ' '; - len += sprintf(page+len, "%s",pd1->name); + len += sprintf(page+len, "%s", pd1->name); - if (pd1 == pp->lurker) - len += sprintf(page+len, " LURK"); - - len += sprintf(page+len,"\n"); + page[len++] = '\n'; } *start = 0; @@ -120,26 +123,26 @@ } static int hardware_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) + int count, int *eof, void *data) { struct parport *pp = (struct parport *)data; int len=0; len += sprintf(page+len, "base:\t0x%lx\n",pp->base); + if (pp->irq == PARPORT_IRQ_NONE) len += sprintf(page+len, "irq:\tnone\n"); else len += sprintf(page+len, "irq:\t%d\n",pp->irq); + if (pp->dma == PARPORT_DMA_NONE) len += sprintf(page+len, "dma:\tnone\n"); else len += sprintf(page+len, "dma:\t%d\n",pp->dma); - -#if 0 len += sprintf(page+len, "modes:\t"); { -#define printmode(x) {if(pp->modes&PARPORT_MODE_##x){len+=sprintf(page+len,"%s%s",f?",":"",#x);f++;}} +#define printmode(x) {if(pp->modes&PARPORT_MODE_PC##x){len+=sprintf(page+len,"%s%s",f?",":"",#x);f++;}} int f = 0; printmode(SPP); printmode(PS2); @@ -149,65 +152,21 @@ printmode(ECPPS2); #undef printmode } - len += sprintf(page+len, "\n"); - - len += sprintf(page+len, "mode:\t"); - if (pp->modes & PARPORT_MODE_ECR) { - switch (r_ecr(pp) >> 5) { - case 0: - len += sprintf(page+len, "SPP"); - if( pp->modes & PARPORT_MODE_PS2 ) - len += sprintf(page+len, ",PS2"); - if( pp->modes & PARPORT_MODE_EPP ) - len += sprintf(page+len, ",EPP"); - break; - case 1: - len += sprintf(page+len, "ECPPS2"); - break; - case 2: - len += sprintf(page+len, "DATAFIFO"); - break; - case 3: - len += sprintf(page+len, "ECP"); - break; - case 4: - len += sprintf(page+len, "ECPEPP"); - break; - case 5: - len += sprintf(page+len, "Reserved?"); - break; - case 6: - len += sprintf(page+len, "TEST"); - break; - case 7: - len += sprintf(page+len, "Configuration"); - break; - } - } else { - len += sprintf(page+len, "SPP"); - if (pp->modes & PARPORT_MODE_PS2) - len += sprintf(page+len, ",PS2"); - if (pp->modes & PARPORT_MODE_EPP) - len += sprintf(page+len, ",EPP"); - } - len += sprintf(page+len, "\n"); -#endif -#if 0 - /* Now no detection, please fix with an external function */ - len += sprintf(page+len, "chipset:\tunknown\n"); -#endif -#ifdef PARPORT_INCLUDE_BENCHMARK - if (pp->speed) - len += sprintf(page+len, "bench:\t%d Bytes/s\n",pp->speed); - else - len += sprintf(page+len, "bench:\tunknown\n"); -#endif + page[len++] = '\n'; *start = 0; *eof = 1; return len; } +static inline void destroy_proc_entry(struct proc_dir_entry *root, + struct proc_dir_entry **d) +{ + proc_unregister(root, (*d)->low_ino); + kfree(*d); + *d = NULL; +} + static struct proc_dir_entry *new_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent, unsigned short ino) @@ -217,6 +176,7 @@ ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL); if (!ent) return NULL; + memset(ent, 0, sizeof(struct proc_dir_entry)); if (mode == S_IFDIR) @@ -224,11 +184,11 @@ else if (mode == 0) mode = S_IFREG | S_IRUGO; - ent->low_ino = ino; ent->name = name; ent->namelen = strlen(name); ent->mode = mode; + if (S_ISDIR(mode)) ent->nlink = 2; else @@ -240,103 +200,95 @@ } -int parport_proc_init() +int parport_proc_init(void) { base = new_proc_entry("parport", S_IFDIR, &proc_root,PROC_PARPORT); - if (base) - return 1; - else { - printk(KERN_ERR "parport: Error creating proc entry /proc/parport\n"); + if (base == NULL) { + printk(KERN_ERR "Unable to initialise /proc/parport.\n"); return 0; } + + return 1; } -int parport_proc_cleanup() +void parport_proc_cleanup(void) { - if (base) - proc_unregister(&proc_root,base->low_ino); - + if (base) proc_unregister(&proc_root,base->low_ino); base = NULL; - - return 0; } int parport_proc_register(struct parport *pp) { - struct proc_dir_entry *ent; - static int conta=0; - char *name; + static const char *proc_msg = KERN_ERR "%s: Trouble with /proc.\n"; - memset(&pp->pdir,0,sizeof(struct parport_dir)); + memset(&pp->pdir, 0, sizeof(struct parport_dir)); - if (!base) { - printk(KERN_ERR "parport: Error entry /proc/parport, not generated?\n"); + if (base == NULL) { + printk(KERN_ERR "parport_proc not initialised yet.\n"); return 1; } - name = pp->pdir.name; - sprintf(name,"%d",conta++); + strncpy(pp->pdir.name, pp->name + strlen("parport"), + sizeof(pp->pdir.name)); - ent = new_proc_entry(name, S_IFDIR, base,0); - if (!ent) { - printk(KERN_ERR "parport: Error registering proc_entry /proc/%s\n",name); + pp->pdir.entry = new_proc_entry(pp->pdir.name, S_IFDIR, base, 0); + if (pp->pdir.entry == NULL) { + printk(proc_msg, pp->name); return 1; } - pp->pdir.entry = ent; - ent = new_proc_entry("irq", S_IFREG | S_IRUGO | S_IWUSR, pp->pdir.entry,0); - if (!ent) { - printk(KERN_ERR "parport: Error registering proc_entry /proc/%s/irq\n",name); + pp->pdir.irq = new_proc_entry("irq", S_IFREG | S_IRUGO | S_IWUSR, + pp->pdir.entry, 0); + if (pp->pdir.irq == NULL) { + printk(proc_msg, pp->name); + destroy_proc_entry(base, &pp->pdir.entry); return 1; } - ent->read_proc = irq_read_proc; - ent->write_proc= irq_write_proc; - ent->data = pp; - pp->pdir.irq = ent; + pp->pdir.irq->read_proc = irq_read_proc; + pp->pdir.irq->write_proc = irq_write_proc; + pp->pdir.irq->data = pp; - ent = new_proc_entry("devices", 0, pp->pdir.entry,0); - if (!ent) { - printk(KERN_ERR "parport: Error registering proc_entry /proc/%s/devices\n",name); + pp->pdir.devices = new_proc_entry("devices", 0, pp->pdir.entry, 0); + if (pp->pdir.devices == NULL) { + printk(proc_msg, pp->name); + destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq); + destroy_proc_entry(base, &pp->pdir.entry); return 1; } - ent->read_proc = devices_read_proc; - ent->data = pp; - pp->pdir.devices = ent; + pp->pdir.devices->read_proc = devices_read_proc; + pp->pdir.devices->data = pp; - ent = new_proc_entry("hardware", 0, pp->pdir.entry,0); - if (!ent) { - printk(KERN_ERR "parport: Error registering proc_entry /proc/%s/hardware\n",name); + pp->pdir.hardware = new_proc_entry("hardware", 0, pp->pdir.entry, 0); + if (pp->pdir.hardware == NULL) { + printk(proc_msg, pp->name); + destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices); + destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq); + destroy_proc_entry(base, &pp->pdir.entry); return 1; } - ent->read_proc = hardware_read_proc; - ent->data = pp; - pp->pdir.hardware = ent; + pp->pdir.hardware->read_proc = hardware_read_proc; + pp->pdir.hardware->data = pp; + return 0; } int parport_proc_unregister(struct parport *pp) { if (pp->pdir.entry) { - if (pp->pdir.irq) { - proc_unregister(pp->pdir.entry, pp->pdir.irq->low_ino); - kfree(pp->pdir.irq); - } + if (pp->pdir.irq) + destroy_proc_entry(pp->pdir.entry, &pp->pdir.irq); - if (pp->pdir.devices) { - proc_unregister(pp->pdir.entry, - pp->pdir.devices->low_ino); - kfree(pp->pdir.devices); - } + if (pp->pdir.devices) + destroy_proc_entry(pp->pdir.entry, &pp->pdir.devices); - if (pp->pdir.hardware) { - proc_unregister(pp->pdir.entry, - pp->pdir.hardware->low_ino); - kfree(pp->pdir.hardware); - } + if (pp->pdir.hardware) + destroy_proc_entry(pp->pdir.entry, &pp->pdir.hardware); + + if (pp->pdir.probe) + destroy_proc_entry(pp->pdir.entry, &pp->pdir.probe); - proc_unregister(base, pp->pdir.entry->low_ino); - kfree(pp->pdir.entry); + destroy_proc_entry(base, &pp->pdir.entry); } return 0; diff -ur --new-file old/linux/drivers/misc/parport_share.c new/linux/drivers/misc/parport_share.c --- old/linux/drivers/misc/parport_share.c Mon Dec 1 23:49:02 1997 +++ new/linux/drivers/misc/parport_share.c Tue Mar 10 23:43:13 1998 @@ -1,14 +1,20 @@ -/* $Id: parport_share.c,v 1.8 1997/11/08 18:55:29 philip Exp $ +/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $ * Parallel-port resource manager code. * * Authors: David Campbell * Tim Waugh - * Jose Renau + * Jose Renau + * Philip Blundell + * Andrea Arcangeli * * based on work by Grant Guenther - * and Philip Blundell + * and Philip Blundell */ +#undef PARPORT_DEBUG_SHARING /* undef for production */ + +#include + #include #include @@ -18,15 +24,18 @@ #include #include #include +#include -#include +#include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif #undef PARPORT_PARANOID +#define PARPORT_DEFAULT_TIMESLICE (HZ/10) + static struct parport *portlist = NULL, *portlist_tail = NULL; static int portcount = 0; @@ -35,21 +44,21 @@ /* Return a list of all the ports we know about. */ struct parport *parport_enumerate(void) { -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (portlist == NULL) { request_module("parport_lowlevel"); #ifdef CONFIG_PNP_PARPORT_MODULE request_module("parport_probe"); #endif /* CONFIG_PNP_PARPORT_MODULE */ } -#endif /* CONFIG_KERNELD */ +#endif /* CONFIG_KMOD */ return portlist; } void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs) { - /* NULL function - Does nothing */ - return; + /* Null function - does nothing. IRQs are pointed here whenever + there is no real handler for them. */ } struct parport *parport_register_port(unsigned long base, int irq, int dma, @@ -58,9 +67,8 @@ struct parport *tmp; /* Check for a previously registered port. - * NOTE: we will ignore irq and dma if we find a previously - * registered device. - */ + NOTE: we will ignore irq and dma if we find a previously + registered device. */ for (tmp = portlist; tmp; tmp = tmp->next) { if (tmp->base == base) return tmp; @@ -79,9 +87,11 @@ tmp->dma = dma; tmp->modes = 0; tmp->next = NULL; - tmp->devices = tmp->cad = tmp->lurker = NULL; + tmp->devices = tmp->cad = NULL; tmp->flags = 0; - tmp->ops = ops; + tmp->ops = ops; + tmp->number = portcount; + spin_lock_init (&tmp->lock); tmp->name = kmalloc(15, GFP_KERNEL); if (!tmp->name) { @@ -91,7 +101,7 @@ } sprintf(tmp->name, "parport%d", portcount); - /* Here we chain the entry to our list. */ + /* Chain the entry to our list. */ if (portlist_tail) portlist_tail->next = tmp; portlist_tail = tmp; @@ -101,6 +111,8 @@ portcount++; tmp->probe_info.class = PARPORT_CLASS_LEGACY; /* assume the worst */ + tmp->waithead = tmp->waittail = NULL; + return tmp; } @@ -146,13 +158,7 @@ { struct pardevice *tmp; - /* We only allow one lurking device. */ if (flags & PARPORT_DEV_LURK) { - if (port->lurker) { - printk(KERN_INFO "%s: refused to register second lurker (%s)\n", - port->name, name); - return NULL; - } if (!pf || !kf) { printk(KERN_INFO "%s: refused to register lurking device (%s) without callbacks\n", port->name, name); return NULL; @@ -189,6 +195,7 @@ tmp->flags = flags; tmp->irq_func = irq_func; port->ops->save_state(port, tmp->state); + tmp->waiting = 0; /* Chain this onto the list */ tmp->prev = NULL; @@ -197,40 +204,44 @@ port->devices->prev = tmp; port->devices = tmp; - if (flags & PARPORT_DEV_LURK) - port->lurker = tmp; - inc_parport_count(); port->ops->inc_use_count(); + init_waitqueue(&tmp->wait_q); + tmp->timeslice = PARPORT_DEFAULT_TIMESLICE; + tmp->waitnext = tmp->waitprev = NULL; + return tmp; } void parport_unregister_device(struct pardevice *dev) { struct parport *port; + unsigned long flags; +#ifdef PARPORT_PARANOID if (dev == NULL) { printk(KERN_ERR "parport_unregister_device: passed NULL\n"); return; } +#endif port = dev->port; if (port->cad == dev) { - printk(KERN_WARNING "%s: refused to unregister currently active device %s.\n", port->name, dev->name); + printk(KERN_WARNING "%s: refused to unregister " + "currently active device %s.\n", port->name, dev->name); return; } - if (port->lurker == dev) - port->lurker = NULL; - + spin_lock_irqsave (&port->lock, flags); if (dev->next) dev->next->prev = dev->prev; if (dev->prev) dev->prev->next = dev->next; else port->devices = dev->next; + spin_unlock_irqrestore (&port->lock, flags); kfree(dev->state); kfree(dev); @@ -247,99 +258,184 @@ int parport_claim(struct pardevice *dev) { - struct pardevice *pd1; + struct pardevice *oldcad; + struct parport *port = dev->port; + unsigned long flags; - if (dev->port->cad == dev) { + if (port->cad == dev) { printk(KERN_INFO "%s: %s already owner\n", dev->port->name,dev->name); return 0; } +try_again: /* Preempt any current device */ - pd1 = dev->port->cad; - if (dev->port->cad) { - if (dev->port->cad->preempt) { - if (dev->port->cad->preempt(dev->port->cad->private)) - return -EAGAIN; - dev->port->ops->save_state(dev->port, dev->state); + if ((oldcad = port->cad)) { + if (oldcad->preempt) { + if (oldcad->preempt(oldcad->private)) + goto blocked; + port->ops->save_state(port, dev->state); } else - return -EAGAIN; + goto blocked; + + if (port->cad != oldcad) { + printk(KERN_WARNING + "%s: %s released port when preempted!\n", + port->name, oldcad->name); + if (port->cad) + goto blocked; + } } - /* Watch out for bad things */ - if (dev->port->cad != pd1) { - printk(KERN_WARNING "%s: death while preempting %s\n", - dev->port->name, dev->name); - if (dev->port->cad) - return -EAGAIN; + /* Can't fail from now on, so mark ourselves as no longer waiting. */ + if (dev->waiting & 1) { + dev->waiting = 0; + + /* Take ourselves out of the wait list again. */ + spin_lock_irqsave (&port->lock, flags); + if (dev->waitprev) + dev->waitprev->waitnext = dev->waitnext; + else + port->waithead = dev->waitnext; + if (dev->waitnext) + dev->waitnext->waitprev = dev->waitprev; + else + port->waittail = dev->waitprev; + spin_unlock_irqrestore (&port->lock, flags); + dev->waitprev = dev->waitnext = NULL; } /* Now we do the change of devices */ - dev->port->cad = dev; + port->cad = dev; /* Swap the IRQ handlers. */ - if (dev->port->irq != PARPORT_IRQ_NONE) { - free_irq(dev->port->irq, pd1?pd1->private:NULL); - request_irq(dev->port->irq, dev->irq_func ? dev->irq_func : - parport_null_intr_func, SA_INTERRUPT, dev->name, - dev->private); + if (port->irq != PARPORT_IRQ_NONE) { + if (oldcad && oldcad->irq_func) { + free_irq(port->irq, oldcad->private); + request_irq(port->irq, parport_null_intr_func, + SA_INTERRUPT, port->name, NULL); + } + if (dev->irq_func) { + free_irq(port->irq, NULL); + request_irq(port->irq, dev->irq_func, + SA_INTERRUPT, dev->name, dev->private); + } } /* Restore control registers */ - dev->port->ops->restore_state(dev->port, dev->state); - + port->ops->restore_state(port, dev->state); + dev->time = jiffies; return 0; + +blocked: + /* If this is the first time we tried to claim the port, register an + interest. This is only allowed for devices sleeping in + parport_claim_or_block(), or those with a wakeup function. */ + if (dev->waiting & 2 || dev->wakeup) { + spin_lock_irqsave (&port->lock, flags); + if (port->cad == NULL) { + /* The port got released in the meantime. */ + spin_unlock_irqrestore (&port->lock, flags); + goto try_again; + } + if (test_and_set_bit(0, &dev->waiting) == 0) { + /* First add ourselves to the end of the wait list. */ + dev->waitnext = NULL; + dev->waitprev = port->waittail; + if (port->waittail) + port->waittail->waitnext = dev; + else { + port->waithead = dev->port->waittail = dev; + } + } + spin_unlock_irqrestore (&port->lock, flags); + } + return -EAGAIN; +} + +int parport_claim_or_block(struct pardevice *dev) +{ + int r; + + /* Signal to parport_claim() that we can wait even without a + wakeup function. */ + dev->waiting = 2; + + /* Try to claim the port. If this fails, we need to sleep. */ + r = parport_claim(dev); + if (r == -EAGAIN) { + unsigned long flags; +#ifdef PARPORT_DEBUG_SHARING + printk(KERN_DEBUG "%s: parport_claim() returned -EAGAIN\n", dev->name); +#endif + save_flags (flags); + cli(); + /* If dev->waiting is clear now, an interrupt + gave us the port and we would deadlock if we slept. */ + if (dev->waiting) { + sleep_on(&dev->wait_q); + r = 1; + } else { + r = 0; +#ifdef PARPORT_DEBUG_SHARING + printk(KERN_DEBUG "%s: didn't sleep in parport_claim_or_block()\n", + dev->name); +#endif + } + restore_flags(flags); +#ifdef PARPORT_DEBUG_SHARING + if (dev->port->cad != dev) + printk(KERN_DEBUG "%s: exiting parport_claim_or_block but %s owns port!\n", dev->name, dev->port->cad?dev->port->cad->name:"nobody"); +#endif + } + dev->waiting = 0; + return r; } void parport_release(struct pardevice *dev) { - struct pardevice *pd1; + struct parport *port = dev->port; + struct pardevice *pd; /* Make sure that dev is the current device */ - if (dev->port->cad != dev) { - printk(KERN_WARNING "%s: %s tried to release parport when not owner\n", dev->port->name, dev->name); + if (port->cad != dev) { + printk(KERN_WARNING "%s: %s tried to release parport " + "when not owner\n", port->name, dev->name); return; } - dev->port->cad = NULL; + port->cad = NULL; /* Save control registers */ - dev->port->ops->save_state(dev->port, dev->state); + port->ops->save_state(port, dev->state); /* Point IRQs somewhere harmless. */ - if (dev->port->irq != PARPORT_IRQ_NONE) { - free_irq(dev->port->irq, dev->private); - request_irq(dev->port->irq, parport_null_intr_func, - SA_INTERRUPT, dev->port->name, NULL); + if (port->irq != PARPORT_IRQ_NONE && dev->irq_func) { + free_irq(port->irq, dev->private); + request_irq(port->irq, parport_null_intr_func, + SA_INTERRUPT, port->name, NULL); } - /* Walk the list, offering a wakeup callback to everybody other - * than the lurker and the device that called us. - */ - for (pd1 = dev->next; pd1; pd1 = pd1->next) { - if (!(pd1->flags & PARPORT_DEV_LURK)) { - if (pd1->wakeup) { - pd1->wakeup(pd1->private); - if (dev->port->cad) - return; - } - } - } - - for (pd1 = dev->port->devices; pd1 && pd1 != dev; pd1 = pd1->next) { - if (!(pd1->flags & PARPORT_DEV_LURK)) { - if (pd1->wakeup) { - pd1->wakeup(pd1->private); - if (dev->port->cad) - return; - } + /* If anybody is waiting, find out who's been there longest and + then wake them up. (Note: no locking required) */ + for (pd = port->waithead; pd; pd = pd->waitnext) { + if (pd->waiting & 2) { + parport_claim(pd); + if (waitqueue_active(&pd->wait_q)) + wake_up(&pd->wait_q); + return; + } else if (pd->wakeup) { + pd->wakeup(pd->private); + if (dev->port->cad) + return; + } else { + printk(KERN_ERR "%s: don't know how to wake %s\n", port->name, pd->name); } } - /* Now give the lurker a chance. - * There must be a wakeup callback because we checked for it - * at registration. - */ - if (dev->port->lurker && (dev->port->lurker != dev)) { - dev->port->lurker->wakeup(dev->port->lurker->private); + /* Nobody was waiting, so walk the list to see if anyone is + interested in being woken up. */ + for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) { + if (pd->wakeup && pd != dev) + pd->wakeup(pd->private); } } diff -ur --new-file old/linux/drivers/net/3c501.c new/linux/drivers/net/3c501.c --- old/linux/drivers/net/3c501.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/3c501.c Tue Feb 10 21:56:43 1998 @@ -470,7 +470,7 @@ if (el_debug > 2) printk(" queued xmit.\n"); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } diff -ur --new-file old/linux/drivers/net/3c503.c new/linux/drivers/net/3c503.c --- old/linux/drivers/net/3c503.c Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/net/3c503.c Thu Feb 19 23:58:40 1998 @@ -675,10 +675,10 @@ struct device *dev = &dev_el2[this_dev]; if (dev->priv != NULL) { /* NB: el2_close() handles free_irq */ + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, EL2_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/3c505.c new/linux/drivers/net/3c505.c --- old/linux/drivers/net/3c505.c Wed Dec 10 18:45:15 1997 +++ new/linux/drivers/net/3c505.c Thu Feb 19 23:58:40 1998 @@ -698,7 +698,7 @@ outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev); if (adapter->current_dma.direction) { - dev_kfree_skb(adapter->current_dma.skb, FREE_WRITE); + dev_kfree_skb(adapter->current_dma.skb); } else { struct sk_buff *skb = adapter->current_dma.skb; if (skb) { @@ -1694,10 +1694,10 @@ for (this_dev = 0; this_dev < ELP_MAX_CARDS; this_dev++) { struct device *dev = &dev_3c505[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, ELP_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/3c507.c new/linux/drivers/net/3c507.c --- old/linux/drivers/net/3c507.c Tue Nov 11 01:17:17 1997 +++ new/linux/drivers/net/3c507.c Tue Feb 10 21:56:43 1998 @@ -493,7 +493,7 @@ outb(0x84, ioaddr + MISC_CTRL); } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ diff -ur --new-file old/linux/drivers/net/3c509.c new/linux/drivers/net/3c509.c --- old/linux/drivers/net/3c509.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/3c509.c Sat Feb 21 03:28:22 1998 @@ -34,7 +34,7 @@ #include -#include +#include /* for CONFIG_MCA */ #include #include #include @@ -47,7 +47,6 @@ #include #include #include -#include /* for CONFIG_MCA */ #include /* for udelay() */ #include @@ -548,7 +547,7 @@ outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); /* Clear the Tx status stack. */ { @@ -864,11 +863,11 @@ for (this_dev = 0; this_dev < MAX_3C_CARDS; this_dev++) { struct device *dev = &dev_3c509[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree_s(dev->priv,sizeof(struct el3_private)); dev->priv = NULL; free_irq(dev->irq, dev); release_region(dev->base_addr, EL3_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/3c523.c new/linux/drivers/net/3c523.c --- old/linux/drivers/net/3c523.c Wed May 14 07:41:08 1997 +++ new/linux/drivers/net/3c523.c Tue Feb 10 21:56:43 1998 @@ -1154,7 +1154,7 @@ elmc_attn586(); dev->trans_start = jiffies; if(!i) { - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); } WAIT_4_SCB_CMD(); if( (p->scb->status & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */ @@ -1179,7 +1179,7 @@ p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); dev->trans_start = jiffies; p->nop_point = next_nop; - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); # endif #else p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len; @@ -1201,7 +1201,7 @@ dev->tbusy = 0; } sti(); - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); #endif } return 0; diff -ur --new-file old/linux/drivers/net/3c59x.c new/linux/drivers/net/3c59x.c --- old/linux/drivers/net/3c59x.c Tue Jan 13 00:28:18 1998 +++ new/linux/drivers/net/3c59x.c Sat Feb 21 03:28:22 1998 @@ -44,7 +44,6 @@ #define RX_RING_SIZE 32 #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ -#include #ifdef MODULE #ifdef MODVERSIONS #include @@ -482,9 +481,11 @@ /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Note: this is the only limit on the number of cards supported!! */ static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,}; +#ifdef MODULE static int full_duplex[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; /* A list of all installed Vortex devices, for removing the driver module. */ static struct device *root_vortex_dev = NULL; +#endif #ifdef MODULE /* Variables to work-around the Compaq PCI BIOS32 problem. */ @@ -1277,7 +1278,7 @@ if (vp->tx_skbuff[entry]) { if (vortex_debug > 0) printk(" %d\n", entry); - dev_kfree_skb(vp->tx_skbuff[entry], FREE_WRITE); + dev_kfree_skb(vp->tx_skbuff[entry]); vp->tx_skbuff[entry] = 0; vp->stats.tx_dropped++; } @@ -1338,7 +1339,7 @@ } else { /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); if (inw(ioaddr + TxFree) > 1536) { dev->tbusy = 0; } else @@ -1348,7 +1349,7 @@ #else /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); if (inw(ioaddr + TxFree) > 1536) { dev->tbusy = 0; } else @@ -1525,7 +1526,7 @@ virt_to_bus(&lp->tx_ring[entry])) break; /* It still hasn't been processed. */ if (lp->tx_skbuff[entry]) { - dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE); + dev_kfree_skb(lp->tx_skbuff[entry]); lp->tx_skbuff[entry] = 0; } /* lp->stats.tx_packets++; Counted below. */ @@ -1543,7 +1544,7 @@ if (status & DMADone) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ dev->tbusy = 0; - dev_kfree_skb (lp->tx_skb, FREE_WRITE); /* Release the transfered buffer */ + dev_kfree_skb (lp->tx_skb); /* Release the transfered buffer */ mark_bh(NET_BH); } #endif @@ -1852,7 +1853,7 @@ #if LINUX_VERSION_CODE < 0x20100 vp->rx_skbuff[i]->free = 1; #endif - dev_kfree_skb (vp->rx_skbuff[i], FREE_WRITE); + dev_kfree_skb (vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } } @@ -1860,7 +1861,7 @@ outl(0, ioaddr + DownListPtr); for (i = 0; i < TX_RING_SIZE; i++) if (vp->tx_skbuff[i]) { - dev_kfree_skb(vp->tx_skbuff[i], FREE_WRITE); + dev_kfree_skb(vp->tx_skbuff[i]); vp->tx_skbuff[i] = 0; } } diff -ur --new-file old/linux/drivers/net/8390.c new/linux/drivers/net/8390.c --- old/linux/drivers/net/8390.c Wed Oct 22 17:27:31 1997 +++ new/linux/drivers/net/8390.c Tue Feb 10 21:56:43 1998 @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include #include #include @@ -185,12 +187,14 @@ /* Mask interrupts from the ethercard. */ outb_p(0x00, e8390_base + EN0_IMR); + disable_irq(dev->irq); synchronize_irq(); if (dev->interrupt) { printk("%s: Tx request while isr active.\n",dev->name); outb_p(ENISR_ALL, e8390_base + EN0_IMR); + enable_irq(dev->irq); ei_local->stat.tx_errors++; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } ei_local->irqlock = 1; @@ -226,6 +230,7 @@ ei_local->irqlock = 0; dev->tbusy = 1; outb_p(ENISR_ALL, e8390_base + EN0_IMR); + enable_irq(dev->irq); ei_local->stat.tx_errors++; return 1; } @@ -272,8 +277,9 @@ /* Turn 8390 interrupts back on. */ ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); + enable_irq(dev->irq); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); ei_local->stat.tx_bytes += send_length; return 0; @@ -608,7 +614,6 @@ static void ei_rx_overrun(struct device *dev) { int e8390_base = dev->base_addr; - unsigned long wait_start_time; unsigned char was_txing, must_resend = 0; struct ei_device *ei_local = (struct ei_device *) dev->priv; @@ -629,9 +634,7 @@ * it "is not a reliable indicator and subsequently should be ignored." * We wait at least 10ms. */ - wait_start_time = jiffies; - while (jiffies - wait_start_time <= 1*HZ/100) - barrier(); + udelay(10*1000); /* * Reset RBCR[01] back to zero as per magic incantation. diff -ur --new-file old/linux/drivers/net/CONFIG new/linux/drivers/net/CONFIG --- old/linux/drivers/net/CONFIG Mon Jan 5 10:41:01 1998 +++ new/linux/drivers/net/CONFIG Thu Jan 1 01:00:00 1970 @@ -1,79 +0,0 @@ -# -# This file is used for selecting non-standard netcard options, and -# need not be modified for typical use. -# -# Drivers are *not* selected in this file, but rather with files -# automatically generated during the top-level kernel configuration. -# -# Special options supported, indexed by their 'config' name: -# -# CONFIG_WD80x3 The Western Digital (SMC) WD80x3 driver -# WD_SHMEM=xxx Forces the address of the shared memory -# CONFIG_NE2000 The NE-[12]000 clone driver. -# PACKETBUF_MEMSIZE Allows an extra-large packet buffer to be -# used. Usually pointless under Linux. -# show_all_SAPROM Show the entire address PROM, not just the -# ethernet address, during boot. -# CONFIG_NE_RW_BUGFIX Patch an obscure bug with a version of the 8390. -# CONFIG_NE_SANITY Double check the internal card xfer address -# against the driver's value. Useful for debugging. -# CONFIG_HPLAN The HP-LAN driver (for 8390-based boards only). -# rw_bugfix Fix the same obscure bug. -# CONFIG_EL2 The 3c503 EtherLink II driver -# EL2_AUI Default to the AUI port instead of the BNC port -# no_probe_nonshared_memory Don't probe for programmed-I/O boards. -# EL2MEMTEST Test shared memory at boot-time. -# CONFIG_PLIP The Crynwr-protocol PL/IP driver -# INITIALTIMEOUTFACTOR Timing parameters. -# MAXTIMEOUTFACTOR -# DE600 The D-Link DE-600 Portable Ethernet Adaptor. -# DE600_IO The DE600 I/O-port address (0x378 == default) -# DE600_IRQ The DE600 IRQ number to use (IRQ7 == default) -# DE600_DEBUG Enable or disable DE600 debugging (default off) -# DE620 The D-Link DE-600 Portable Ethernet Adaptor. -# DE620_IO The DE620 I/O-port address (0x378 == default) -# DE620_IRQ The DE620 IRQ number to use (IRQ7 == default) -# DE620_DEBUG Enable or disable DE600 debugging (default off) -# DEPCA The DIGITAL series of LANCE based Ethernet Cards -# (DEPCA, DE100, DE200/1/2, DE210, DE422 (EISA)) -# EWRK3 The DIGITAL series of AT Ethernet Cards (DE203/4/5) -# EWRK3_DEBUG Set the desired debug level -# -# DE4x5 The DIGITAL series of PCI/EISA Ethernet Cards, -# DE425, DE434, DE435, DE450, DE500 -# DE4X5_DEBUG Set the desired debug level -# DEC_ONLY Allows driver to work with DIGITAL cards only - -# see linux/drivers/net/README.de4x5 -# DE4X5_DO_MEMCPY Forces the Intels to use memory copies into sk_buffs -# rather than straight DMA. -# DE4X5_PARM See linux/Documentation/networking/de4x5.txt or the -# driver source code for detailed information on setting -# duplex and speed/media on individual adapters. -# -# DEFXX The DIGITAL series of FDDI EISA (DEFEA) and PCI (DEFPA) -# controllers -# DEFXX_DEBUG Set the desired debug level -# -# TULIP Tulip (dc21040/dc21041/ds21140) driver -# TULIP_PORT specify default if_port -# 0: 10TP -# 1: 100Tx(ds21140)/AUI(dc2104x) -# 2: BNC(dc2104x) -# TULIP_FIX_PORT don't change if_port automatically if defined -# TULIP_MAX_CARDS maximum number of probed card -# - -# The following options exist, but cannot be set in this file. -# lance.c -# LANCE_DMA Change the default DMA to other than DMA5. -# 8390.c -# NO_PINGPONG Disable ping-pong transmit buffers. - - -# Most drivers also have a *_DEBUG setting that may be adjusted. -# The 8390 drivers share the EI_DEBUG setting. - -# General options for Space.c -CONFIG_Space.o = # -DETH0_ADDR=0x300 -DETH0_IRQ=11 -CONFIG_3c503.o = # -DEL2_AUI -CONFIG_wd.o = # -DWD_SHMEM=0xDD000 diff -ur --new-file old/linux/drivers/net/Config.in new/linux/drivers/net/Config.in --- old/linux/drivers/net/Config.in Sun Jan 4 19:40:16 1998 +++ new/linux/drivers/net/Config.in Wed Mar 11 20:40:11 1998 @@ -15,8 +15,8 @@ tristate 'Dummy net driver support' CONFIG_DUMMY tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_NETLINK_DEV" = "y" -o "$CONFIG_NETLINK_DEV" = "m" ]; then - dep_tristate 'Ethertap network tap' CONFIG_ETHERTAP $CONFIG_NETLINK_DEV + if [ "$CONFIG_NETLINK" = "y" ]; then + tristate 'Ethertap network tap' CONFIG_ETHERTAP fi fi # @@ -49,10 +49,10 @@ if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then tristate 'WD80*3 support' CONFIG_WD80x3 if [ "$CONFIG_MCA" = "y" ]; then - tristate 'SMC Ultra MCA support' CONFIG_ULTRA - else - tristate 'SMC Ultra support' CONFIG_ULTRA + tristate 'SMC Ultra MCA support' CONFIG_ULTRAMCA fi + tristate 'SMC Ultra support' CONFIG_ULTRA + tristate 'SMC Ultra32 EISA support' CONFIG_ULTRA32 tristate 'SMC 9194 support' CONFIG_SMC9194 fi bool 'Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL @@ -183,7 +183,7 @@ bool 'WAN drivers' CONFIG_WAN_DRIVERS if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then dep_tristate 'Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS - if [ "$CONFIG_VENDOR_SANGOMA" = "y" ]; then + if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR diff -ur --new-file old/linux/drivers/net/Makefile new/linux/drivers/net/Makefile --- old/linux/drivers/net/Makefile Mon Jan 5 10:41:01 1998 +++ new/linux/drivers/net/Makefile Wed Mar 11 20:40:11 1998 @@ -3,10 +3,6 @@ # Makefile for the Linux network (ethercard) device drivers. # -# This will go away in some future future: hidden configuration files -# are difficult for users to deal with. -include CONFIG - SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) hamradio @@ -34,7 +30,7 @@ ifeq ($(CONFIG_ISDN),m) ifeq ($(CONFIG_ISDN_PPP),y) CONFIG_SLHC_MODULE = y - CONFIG_PPPDEF_BUILTIN = y + CONFIG_PPPDEF_MODULE = y endif endif endif @@ -92,6 +88,22 @@ endif endif +ifeq ($(CONFIG_ARM_AM79C961A),y) +L_OBJS += am79c961a.o +else + ifeq ($(CONFIG_ARM_AM79C961A),m) + M_OBJS += am79c961a.o + endif +endif + +ifeq ($(CONFIG_ARM_ETHERH),y) +CONFIG_8390_BUILTIN = y +else + ifeq ($(CONFIG_ARM_ETHERH),m) + CONFIG_8390_MODULE = y + endif +endif + ifeq ($(CONFIG_WD80x3),y) L_OBJS += wd.o @@ -146,9 +158,6 @@ ifeq ($(CONFIG_ULTRA),y) L_OBJS += smc-ultra.o CONFIG_8390_BUILTIN = y - ifeq ($(CONFIG_MCA),y) - L_OBJS += smc-mca.o - endif else ifeq ($(CONFIG_ULTRA),m) CONFIG_8390_MODULE = y @@ -156,6 +165,26 @@ endif endif +ifeq ($(CONFIG_ULTRAMCA),y) +L_OBJS += smc-mca.o +CONFIG_8390_BUILTIN = y +else + ifeq ($(CONFIG_ULTRAMCA),m) + CONFIG_8390_MODULE = y + M_OBJS += smc-mca.o + endif +endif + +ifeq ($(CONFIG_ULTRA32),y) +L_OBJS += smc-ultra32.o +CONFIG_8390_BUILTIN = y +else + ifeq ($(CONFIG_ULTRA32),m) + CONFIG_8390_MODULE = y + M_OBJS += smc-ultra32.o + endif +endif + ifeq ($(CONFIG_E2100),y) L_OBJS += e2100.o CONFIG_8390_BUILTIN = y @@ -185,8 +214,11 @@ endif endif +# bsd_comp.o is *always* a module, for some undocumented reason +# (perhaps licensing). ifeq ($(CONFIG_PPP),y) LX_OBJS += ppp.o +M_OBJS += bsd_comp.o CONFIG_SLHC_BUILTIN = y CONFIG_PPPDEF_BUILTIN = y else @@ -194,13 +226,10 @@ CONFIG_SLHC_MODULE = y CONFIG_PPPDEF_MODULE = y MX_OBJS += ppp.o + M_OBJS += bsd_comp.o endif endif -ifdef CONFIG_PPP - M_OBJS += bsd_comp.o ppp_deflate.o -endif - ifeq ($(CONFIG_SLIP),y) L_OBJS += slip.o ifeq ($(CONFIG_SLIP_COMPRESSED),y) @@ -563,9 +592,11 @@ endif # if anything built-in uses ppp_deflate, then build it into the kernel also. -# If not, but a module uses it, build as a module: +# If not, but a module uses it, build as a module. +# ... NO!!! ppp_deflate.o does not work as resident; +# it works only as a module! ifdef CONFIG_PPPDEF_BUILTIN -LX_OBJS += ppp_deflate.o +MX_OBJS += ppp_deflate.o else ifdef CONFIG_PPPDEF_MODULE MX_OBJS += ppp_deflate.o diff -ur --new-file old/linux/drivers/net/Space.c new/linux/drivers/net/Space.c --- old/linux/drivers/net/Space.c Tue Dec 9 18:49:58 1997 +++ new/linux/drivers/net/Space.c Wed Mar 11 20:40:11 1998 @@ -43,6 +43,7 @@ extern int tulip_probe(struct device *dev); extern int hp100_probe(struct device *dev); extern int ultra_probe(struct device *dev); +extern int ultra32_probe(struct device *dev); extern int ultramca_probe(struct device *dev); extern int wd_probe(struct device *dev); extern int el2_probe(struct device *dev); @@ -135,9 +136,12 @@ #endif #if defined(CONFIG_ULTRA) && ultra_probe(dev) -#if defined(CONFIG_MCA) +#endif +#if defined(CONFIG_ULTRAMCA) && ultramca_probe(dev) #endif +#if defined(CONFIG_ULTRA32) + && ultra32_probe(dev) #endif #if defined(CONFIG_SMC9194) && smc_init(dev) @@ -277,6 +281,12 @@ #ifdef CONFIG_MIPS_JAZZ_SONIC && sonic_probe(dev) #endif +#ifdef CONFIG_ARCH_ACORN + && acorn_ethif_probe(dev) +#endif +#ifdef CONFIG_ARM_AM79C961A + && am79c961_probe(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 Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/a2065.c Tue Feb 10 21:56:43 1998 @@ -630,7 +630,7 @@ /* Kick the lance: transmit now */ ll->rdp = LE_C0_INEA | LE_C0_TDMD; dev->trans_start = jiffies; - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); if (TX_BUFFS_AVAIL) dev->tbusy = 0; diff -ur --new-file old/linux/drivers/net/ac3200.c new/linux/drivers/net/ac3200.c --- old/linux/drivers/net/ac3200.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/ac3200.c Thu Feb 19 23:58:40 1998 @@ -366,12 +366,12 @@ for (this_dev = 0; this_dev < MAX_AC32_CARDS; this_dev++) { struct device *dev = &dev_ac32[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; /* Someday free_irq may be in ac_close_card() */ free_irq(dev->irq, dev); release_region(dev->base_addr, AC_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/am79c961a.c new/linux/drivers/net/am79c961a.c --- old/linux/drivers/net/am79c961a.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/am79c961a.c Tue Feb 17 00:50:21 1998 @@ -0,0 +1,638 @@ +/* + * linux/drivers/net/am79c961.c + * + * Derived from various things including skeleton.c + * + * R.M.King 1995. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define TX_BUFFERS 15 +#define RX_BUFFERS 25 + +#include "am79c961a.h" + +static unsigned int net_debug = NET_DEBUG; +static void am79c961_setmulticastlist (struct device *dev); + +static char *version = "am79c961 ethernet driver (c) 1995 R.M.King v0.00\n"; + +static void write_rreg (unsigned long base, unsigned int reg, unsigned short val) +{ + __asm__(" + strh %1, [%2] @ NET_RAP + strh %0, [%2, #-4] @ NET_RDP + " : : "r" (val), "r" (reg), "r" (0xf0000464)); +} + +static inline void +write_ireg (unsigned long base, unsigned int reg, unsigned short val) +{ + __asm__(" + strh %1, [%2] @ NET_RAP + strh %0, [%2, #8] @ NET_RDP + " : : "r" (val), "r" (reg), "r" (0xf0000464)); +} + +#define am_writeword(dev,off,val)\ + __asm__("\ + strh %0, [%1]\ + " : : "r" ((val) & 0xffff), "r" (0xe0000000 + ((off) << 1))); + +static inline void am_writebuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length) +{ + offset = 0xe0000000 + (offset << 1); + length = (length + 1) & ~1; + if ((int)buf & 2) { + __asm__ __volatile__(" + strh %2, [%0], #4 + " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); + buf += 2; + length -= 2; + } + while (length > 8) + { + unsigned int tmp, tmp2; + __asm__ __volatile__(" + ldmia %1!, {%2, %3} + strh %2, [%0], #4 + mov %2, %2, lsr #16 + strh %2, [%0], #4 + strh %3, [%0], #4 + mov %3, %3, lsr #16 + strh %3, [%0], #4 + " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2) + : "0" (offset), "1" (buf)); + length -= 8; + } + while (length > 0) { + __asm__ __volatile__(" + strh %2, [%0], #4 + " : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8))); + buf += 2; + length -= 2; + } +} + +static inline unsigned short +read_rreg (unsigned int base_addr, unsigned int reg) +{ + unsigned short v; + __asm__(" + strh %1, [%2] @ NET_RAP + ldrh %0, [%2, #-4] @ NET_IDP + " : "=r" (v): "r" (reg), "r" (0xf0000464)); + return v; +} + +static inline unsigned short am_readword (struct device *dev, unsigned long off) +{ + unsigned long address = 0xe0000000 + (off << 1); + unsigned short val; + + __asm__(" + ldrh %0, [%1] + " : "=r" (val): "r" (address)); + return val; +} + +static inline void am_readbuffer(struct device *dev, unsigned int offset, unsigned char *buf, unsigned int length) +{ + offset = 0xe0000000 + (offset << 1); + length = (length + 1) & ~1; + if ((int)buf & 2) { + unsigned int tmp; + __asm__ __volatile__(" + ldrh %2, [%0], #4 + strb %2, [%1], #1 + mov %2, %2, lsr #8 + strb %2, [%1], #1 + " : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf)); + length -= 2; + } + while (length > 8) { + unsigned int tmp, tmp2, tmp3; + __asm__ __volatile__(" + ldrh %2, [%0], #4 + ldrh %3, [%0], #4 + orr %2, %2, %3, lsl #16 + ldrh %3, [%0], #4 + ldrh %4, [%0], #4 + orr %3, %3, %4, lsl #16 + stmia %1!, {%2, %3} + " : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3) + : "0" (offset), "1" (buf)); + length -= 8; + } + while (length > 0) { + unsigned int tmp; + __asm__ __volatile__(" + ldrh %2, [%0], #4 + strb %2, [%1], #1 + mov %2, %2, lsr #8 + strb %2, [%1], #1 + " : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf)); + length -= 2; + } +} + +/* + * From here on is mostly non ARM specific. Watch the fact it knows + * the chip can hit all memory (kmalloc). + */ + +static int am79c961_ramtest(struct device *dev, unsigned int val) +{ + unsigned char *buffer = kmalloc (65536, GFP_KERNEL); + int i, error = 0, errorcount = 0; + + if (!buffer) + return 0; + memset (buffer, val, 65536); + am_writebuffer(dev, 0, buffer, 65536); + memset (buffer, val ^ 255, 65536); + am_readbuffer(dev, 0, buffer, 65536); + for (i = 0; i < 65536; i++) { + if (buffer[i] != val && !error) { + printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i); + error = 1; + errorcount ++; + } else if (error && buffer[i] == val) { + printk ("%05X\n", i); + error = 0; + } + } + if (error) + printk ("10000\n"); + kfree (buffer); + return errorcount; +} + +static void am79c961_init_for_open(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *)dev->priv; + unsigned long hdr_addr, first_free_addr; + unsigned long flags; + unsigned char *p; + int i; + + save_flags_cli (flags); + + write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ + write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP); + + restore_flags (flags); + + first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16; + hdr_addr = 0; + + priv->rxhead = 0; + priv->rxtail = 0; + priv->rxhdr = hdr_addr; + + for (i = 0; i < RX_BUFFERS; i++) + { + priv->rxbuffer[i] = first_free_addr; + am_writeword (dev, hdr_addr, first_free_addr); + am_writeword (dev, hdr_addr + 2, RMD_OWN); + am_writeword (dev, hdr_addr + 4, (-1600)); + am_writeword (dev, hdr_addr + 6, 0); + first_free_addr += 1600; + hdr_addr += 8; + } + priv->txhead = 0; + priv->txtail = 0; + priv->txhdr = hdr_addr; + for (i = 0; i < TX_BUFFERS; i++) + { + priv->txbuffer[i] = first_free_addr; + am_writeword (dev, hdr_addr, first_free_addr); + am_writeword (dev, hdr_addr + 2, 0); + am_writeword (dev, hdr_addr + 4, 0); + am_writeword (dev, hdr_addr + 6, 0); + first_free_addr += 1600; + hdr_addr += 8; + } + + for (i = LADRL; i <= LADRH; i++) + write_rreg (dev->base_addr, i, 0); + + for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) + write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); + + i = MODE_PORT0; + if (dev->flags & IFF_PROMISC) + i |= MODE_PROMISC; + + write_rreg (dev->base_addr, MODE, i); + write_rreg (dev->base_addr, BASERXL, priv->rxhdr); + write_rreg (dev->base_addr, BASERXH, 0); + write_rreg (dev->base_addr, BASETXL, priv->txhdr); + write_rreg (dev->base_addr, BASERXH, 0); + write_rreg (dev->base_addr, POLLINT, 0); + write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); + write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); + write_rreg (dev->base_addr, CSR0, CSR0_STOP); + write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM); + write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT); +} + +static int am79c961_init(struct device *dev) +{ + unsigned long flags; + + am79c961_ramtest(dev, 0x66); + am79c961_ramtest(dev, 0x99); + + save_flags_cli (flags); + + write_ireg (dev->base_addr, 2, 0x4000); /* autoselect media */ + write_rreg (dev->base_addr, CSR0, CSR0_STOP); + write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); + + restore_flags (flags); + + return 0; +} + +/* + * This is the real probe routine. + */ + +static int am79c961_probe1(struct device *dev) +{ + static unsigned version_printed = 0; + struct dev_priv *priv; + int i; + + if (!dev->priv) + { + dev->priv = kmalloc (sizeof (struct dev_priv), GFP_KERNEL); + if (!dev->priv) + return -ENOMEM; + } + + priv = (struct dev_priv *) dev->priv; + memset (priv, 0, sizeof(struct dev_priv)); + + /* + * The PNP initialisation should have been done by the ether bootp loader. + */ + + inb ((dev->base_addr + NET_RESET) >> 1); /* reset the device */ + + udelay (5); + + if (inb (dev->base_addr >> 1) != 0x08 || + inb ((dev->base_addr >> 1) + 1) != 00 || + inb ((dev->base_addr >> 1) + 2) != 0x2b) + { + kfree (dev->priv); + dev->priv = NULL; + return -ENODEV; + } + + /* + * Ok, we've found a valid hw ID + */ + + if (net_debug && version_printed++ == 0) + printk (KERN_INFO "%s", version); + + printk(KERN_INFO "%s: am79c961 found [%04lx, %d] ", dev->name, dev->base_addr, dev->irq); + request_region (dev->base_addr, 0x18, "am79c961"); + + /* Retrive and print the ethernet address. */ + for (i = 0; i < 6; i++) + { + dev->dev_addr[i] = inb ((dev->base_addr >> 1) + i) & 0xff; + printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); + } + + if (am79c961_init(dev)) + { + kfree (dev->priv); + dev->priv = NULL; + return -ENODEV; + } + + dev->open = am79c961_open; + dev->stop = am79c961_close; + dev->hard_start_xmit = am79c961_sendpacket; + dev->get_stats = am79c961_getstats; + dev->set_multicast_list = am79c961_setmulticastlist; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + return 0; +} + +int am79c961_probe(struct device *dev) +{ + static int initialised = 0; + + if (initialised) + return -ENODEV; + initialised = 1; + + dev->base_addr = 0x220; + dev->irq = 3; + + return am79c961_probe1(dev); +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * sometime after booting when the 'ifconfig' program is run. + * + * This routine should set everything up anew at each open, even + * registers that "should" only need to be set once at boot, so that + * there is non-reboot way to recover if something goes wrong. + */ + +static int am79c961_open(struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *)dev->priv; + + MOD_INC_USE_COUNT; + + memset (&priv->stats, 0, sizeof (priv->stats)); + + if (request_irq(dev->irq, am79c961_interrupt, 0, "am79c961", dev)) + return -EAGAIN; + + am79c961_init_for_open(dev); + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + return 0; +} + +/* + * The inverse routine to am79c961_open(). + */ + +static int am79c961_close(struct device *dev) +{ + dev->tbusy = 1; + dev->start = 0; + + am79c961_init(dev); + free_irq (dev->irq, dev); + + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Get the current statistics. This may be called with the card open or + * closed. + */ + +static struct enet_statistics *am79c961_getstats (struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *)dev->priv; + return &priv->stats; +} + +/* + * Set or clear promiscuous/multicast mode filter for this adaptor. + * + * We don't attempt any packet filtering. The card may have a SEEQ 8004 + * in which does not have the other ethernet address registers present... + */ + +static void am79c961_setmulticastlist (struct device *dev) +{ + unsigned long flags; + int i; + + dev->flags &= ~IFF_ALLMULTI; + + i = MODE_PORT0; + if (dev->flags & IFF_PROMISC) + i |= MODE_PROMISC; + + save_flags_cli (flags); + write_rreg (dev->base_addr, MODE, i); + restore_flags (flags); +} + +/* + * Transmit a packet + */ + +static int am79c961_sendpacket(struct sk_buff *skb, struct device *dev) +{ + struct dev_priv *priv = (struct dev_priv *)dev->priv; + + if (!dev->tbusy) + { +again: + if (!test_and_set_bit(0, (void*)&dev->tbusy)) + { + unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned int hdraddr, bufaddr; + unsigned long flags; + + hdraddr = priv->txhdr + (priv->txhead << 3); + bufaddr = priv->txbuffer[priv->txhead]; + priv->txhead ++; + if (priv->txhead >= TX_BUFFERS) + priv->txhead = 0; + + am_writebuffer (dev, bufaddr, skb->data, length); + am_writeword (dev, hdraddr + 4, -length); + am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); + + save_flags_cli (flags); + write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA); + dev->trans_start = jiffies; + restore_flags (flags); + + if (!(am_readword (dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)) + dev->tbusy = 0; + dev_kfree_skb (skb, FREE_WRITE); + return 0; + } + else + { + printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name); + return 1; + } + } + else + { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 5) + return 1; + printk (KERN_WARNING "%s: transmit timed out, network cable problem?\n", dev->name); + /* Try to restart the adaptor. */ + dev->tbusy = 0; + dev->trans_start = jiffies; + goto again; + } +} + +static void am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct device *dev = (struct device *)dev_id; + struct dev_priv *priv = (struct dev_priv *)dev->priv; + unsigned int status; + +#if NET_DEBUG > 1 + if(net_debug & DEBUG_INT) + printk(KERN_DEBUG "am79c961irq: %d ", irq); +#endif + + dev->interrupt = 1; + status = read_rreg (dev->base_addr, CSR0); + write_rreg (dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA)); + + if (status & CSR0_RINT) /* Got a packet(s). */ + am79c961_rx (dev, priv); + if (status & CSR0_TINT) /* Packets transmitted */ + am79c961_tx (dev, priv); + if (status & CSR0_MISS) + priv->stats.rx_dropped ++; + + dev->interrupt = 0; + +#if NET_DEBUG > 1 + if(net_debug & DEBUG_INT) + printk("done\n"); +#endif +} + +/* + * If we have a good packet(s), get it/them out of the buffers. + */ + +static void am79c961_rx(struct device *dev, struct dev_priv *priv) +{ + unsigned long hdraddr; + unsigned long pktaddr; + + do + { + unsigned long status; + struct sk_buff *skb; + int len; + + hdraddr = priv->rxhdr + (priv->rxtail << 3); + pktaddr = priv->rxbuffer[priv->rxtail]; + + status = am_readword (dev, hdraddr + 2); + if (status & RMD_OWN) /* do we own it? */ + break; + + priv->rxtail ++; + if (priv->rxtail >= RX_BUFFERS) + priv->rxtail = 0; + + if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) + { + am_writeword (dev, hdraddr + 2, RMD_OWN); + priv->stats.rx_errors ++; + if (status & RMD_ERR) + { + if (status & RMD_FRAM) + priv->stats.rx_frame_errors ++; + if (status & RMD_CRC) + priv->stats.rx_crc_errors ++; + } + else if (status & RMD_STP) + priv->stats.rx_length_errors ++; + continue; + } + + len = am_readword (dev, hdraddr + 6); + skb = dev_alloc_skb (len + 2); + + if (skb) { + unsigned char *buf; + + skb->dev = dev; + skb_reserve (skb, 2); + buf = skb_put (skb, len); + + am_readbuffer (dev, pktaddr, buf, len); + am_writeword (dev, hdraddr + 2, RMD_OWN); + skb->protocol = eth_type_trans(skb, dev); + netif_rx (skb); + priv->stats.rx_packets ++; + } else { + am_writeword (dev, hdraddr + 2, RMD_OWN); + printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name); + priv->stats.rx_dropped ++; + break; + } + } while (1); +} + +/* + * Update stats for the transmitted packet + */ + +static void am79c961_tx(struct device *dev, struct dev_priv *priv) +{ + do { + unsigned long hdraddr; + unsigned long status; + + hdraddr = priv->txhdr + (priv->txtail << 3); + status = am_readword (dev, hdraddr + 2); + if (status & TMD_OWN) + break; + + priv->txtail ++; + if (priv->txtail >= TX_BUFFERS) + priv->txtail = 0; + + if (status & TMD_ERR) { + unsigned long status2; + + priv->stats.tx_errors ++; + + status2 = am_readword (dev, hdraddr + 6); + am_writeword (dev, hdraddr + 6, 0); + + if (status2 & TST_RTRY) + priv->stats.collisions += 1; + if (status2 & TST_LCOL) + priv->stats.tx_window_errors ++; + if (status2 & TST_LCAR) + priv->stats.tx_carrier_errors ++; + if (status2 & TST_UFLO) + priv->stats.tx_fifo_errors ++; + continue; + } + priv->stats.tx_packets ++; + } while (priv->txtail != priv->txhead); + + dev->tbusy = 0; + mark_bh (NET_BH); +} + diff -ur --new-file old/linux/drivers/net/am79c961a.h new/linux/drivers/net/am79c961a.h --- old/linux/drivers/net/am79c961a.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/am79c961a.h Tue Feb 17 00:50:21 1998 @@ -0,0 +1,128 @@ +/* + * linux/drivers/net/am79c961.h + */ + +#ifndef _LINUX_am79c961a_H +#define _LINUX_am79c961a_H + +/* use 0 for production, 1 for verification, >2 for debug. debug flags: */ +#define DEBUG_TX 2 +#define DEBUG_RX 4 +#define DEBUG_INT 8 +#define DEBUG_IC 16 +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +#define NET_UID 0 +#define NET_RDP 0x10 +#define NET_RAP 0x12 +#define NET_RESET 0x14 +#define NET_IDP 0x16 + +/* + * RAP registers + */ +#define CSR0 0 +#define CSR0_INIT 0x0001 +#define CSR0_STRT 0x0002 +#define CSR0_STOP 0x0004 +#define CSR0_TDMD 0x0008 +#define CSR0_TXON 0x0010 +#define CSR0_RXON 0x0020 +#define CSR0_IENA 0x0040 +#define CSR0_INTR 0x0080 +#define CSR0_IDON 0x0100 +#define CSR0_TINT 0x0200 +#define CSR0_RINT 0x0400 +#define CSR0_MERR 0x0800 +#define CSR0_MISS 0x1000 +#define CSR0_CERR 0x2000 +#define CSR0_BABL 0x4000 +#define CSR0_ERR 0x8000 + +#define CSR3 3 +#define CSR3_EMBA 0x0008 +#define CSR3_DXMT2PD 0x0010 +#define CSR3_LAPPEN 0x0020 +#define CSR3_IDONM 0x0100 +#define CSR3_TINTM 0x0200 +#define CSR3_RINTM 0x0400 +#define CSR3_MERRM 0x0800 +#define CSR3_MISSM 0x1000 +#define CSR3_BABLM 0x4000 +#define CSR3_MASKALL 0x5F00 + +#define LADRL 8 +#define LADRM1 9 +#define LADRM2 10 +#define LADRH 11 +#define PADRL 12 +#define PADRM 13 +#define PADRH 14 + +#define MODE 15 +#define MODE_DISRX 0x0001 +#define MODE_DISTX 0x0002 +#define MODE_LOOP 0x0004 +#define MODE_DTCRC 0x0008 +#define MODE_COLL 0x0010 +#define MODE_DRETRY 0x0020 +#define MODE_INTLOOP 0x0040 +#define MODE_PORT0 0x0080 +#define MODE_DRXPA 0x2000 +#define MODE_DRXBA 0x4000 +#define MODE_PROMISC 0x8000 + +#define BASERXL 24 +#define BASERXH 25 +#define BASETXL 30 +#define BASETXH 31 + +#define POLLINT 47 + +#define SIZERXR 76 +#define SIZETXR 78 + +#define RMD_ENP 0x0100 +#define RMD_STP 0x0200 +#define RMD_CRC 0x0800 +#define RMD_FRAM 0x2000 +#define RMD_ERR 0x4000 +#define RMD_OWN 0x8000 + +#define TMD_ENP 0x0100 +#define TMD_STP 0x0200 +#define TMD_MORE 0x1000 +#define TMD_ERR 0x4000 +#define TMD_OWN 0x8000 + +#define TST_RTRY 0x0200 +#define TST_LCAR 0x0400 +#define TST_LCOL 0x1000 +#define TST_UFLO 0x4000 + +struct dev_priv { + struct enet_statistics stats; + unsigned long rxbuffer[RX_BUFFERS]; + unsigned long txbuffer[TX_BUFFERS]; + unsigned char txhead; + unsigned char txtail; + unsigned char rxhead; + unsigned char rxtail; + unsigned long rxhdr; + unsigned long txhdr; +}; + +extern int am79c961_probe (struct device *dev); +static int am79c961_probe1 (struct device *dev); +static int am79c961_open (struct device *dev); +static int am79c961_sendpacket (struct sk_buff *skb, struct device *dev); +static void am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static void am79c961_rx (struct device *dev, struct dev_priv *priv); +static void am79c961_tx (struct device *dev, struct dev_priv *priv); +static int am79c961_close (struct device *dev); +static struct enet_statistics *am79c961_getstats (struct device *dev); +static void am79c961_setmulticastlist (struct device *dev); + +#endif diff -ur --new-file old/linux/drivers/net/apricot.c new/linux/drivers/net/apricot.c --- old/linux/drivers/net/apricot.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/apricot.c Tue Feb 10 21:56:43 1998 @@ -407,7 +407,7 @@ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; struct sk_buff *skb = ((struct sk_buff *)(tx_cmd->tbd->data)) -1; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); lp->stats.tx_errors++; lp->stats.tx_aborted_errors++; @@ -615,7 +615,7 @@ printk ("%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name); lp->stats.tx_dropped++; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } else { @@ -790,7 +790,7 @@ struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; struct sk_buff *skb = ((struct sk_buff *)(tx_cmd->tbd->data)) -1; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); if ((ptr->status) & STAT_OK) { diff -ur --new-file old/linux/drivers/net/arc-rimi.c new/linux/drivers/net/arc-rimi.c --- old/linux/drivers/net/arc-rimi.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/arc-rimi.c Sat Feb 21 03:28:22 1998 @@ -26,7 +26,6 @@ #include -#include #include #include @@ -479,7 +478,7 @@ if (out->skb) { lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb,FREE_WRITE); + dev_kfree_skb(out->skb); } out->skb=NULL; diff -ur --new-file old/linux/drivers/net/arcnet.c new/linux/drivers/net/arcnet.c --- old/linux/drivers/net/arcnet.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/arcnet.c Tue Feb 10 21:56:44 1998 @@ -636,7 +636,7 @@ if (lp->outgoing.skb) { - dev_kfree_skb(lp->outgoing.skb,FREE_WRITE); + dev_kfree_skb(lp->outgoing.skb); lp->stats.tx_dropped++; } lp->outgoing.skb=NULL; @@ -748,7 +748,7 @@ /* done right away */ lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb,FREE_WRITE); + dev_kfree_skb(out->skb); out->skb=NULL; if (arcnet_go_tx(dev,1)) @@ -797,7 +797,7 @@ if (out->skb) { lp->stats.tx_bytes += skb->len; - dev_kfree_skb(out->skb,FREE_WRITE); + dev_kfree_skb(out->skb); } out->skb=NULL; } @@ -1101,7 +1101,7 @@ in->sequence,arcsoft->split_flag, arcsoft->sequence); lp->aborted_seq=arcsoft->sequence; - kfree_skb(in->skb,FREE_WRITE); + kfree_skb(in->skb); lp->stats.rx_errors++; lp->stats.rx_missed_errors++; in->skb=NULL; @@ -1198,7 +1198,7 @@ BUGMSG(D_EXTRA,"wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", saddr,in->sequence,arcsoft->sequence, arcsoft->split_flag); - kfree_skb(in->skb,FREE_WRITE); + kfree_skb(in->skb); in->skb=NULL; lp->stats.rx_errors++; lp->stats.rx_missed_errors++; @@ -1216,7 +1216,7 @@ arcsoft->sequence); lp->stats.rx_errors++; lp->stats.rx_missed_errors++; - kfree_skb(in->skb,FREE_WRITE); + kfree_skb(in->skb); } in->sequence=arcsoft->sequence; @@ -1288,7 +1288,7 @@ in->sequence,arcsoft->split_flag, arcsoft->sequence); lp->aborted_seq=arcsoft->sequence; - kfree_skb(in->skb,FREE_WRITE); + kfree_skb(in->skb); in->skb=NULL; lp->stats.rx_errors++; lp->stats.rx_missed_errors++; @@ -1434,7 +1434,9 @@ struct ClientData *head = (struct ClientData *)skb->data; struct device *dev=skb->dev; struct arcnet_local *lp=(struct arcnet_local *)(dev->priv); +#ifdef CONFIG_INET int status; +#endif /* * Only ARP and IP are currently supported @@ -1583,7 +1585,7 @@ length); BUGMSG(D_NORMAL,"transmit aborted.\n"); - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); lp->intx--; return 0; } @@ -1613,7 +1615,7 @@ (*lp->prepare_tx)(dev, &proto, 1, skb->data, length-1, daddr, 0, offset); - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); if (arcnet_go_tx(dev,1)) { @@ -1740,7 +1742,7 @@ hdr->daddr,0,0); /* done right away */ - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); if (arcnet_go_tx(dev,1)) { @@ -1752,7 +1754,7 @@ { BUGMSG(D_NORMAL,"packet too long (length=%d)\n", length); - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); lp->stats.tx_dropped++; arcnet_tx_done(lp->adev, lp); } diff -ur --new-file old/linux/drivers/net/ariadne.c new/linux/drivers/net/ariadne.c --- old/linux/drivers/net/ariadne.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/ariadne.c Tue Feb 10 21:56:44 1998 @@ -655,7 +655,7 @@ priv->tx_ring[entry]->TMD1 = (priv->tx_ring[entry]->TMD1&0xff00)|TF_OWN|TF_STP|TF_ENP; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); priv->cur_tx++; if ((priv->cur_tx >= TX_RING_SIZE) && (priv->dirty_tx >= TX_RING_SIZE)) { diff -ur --new-file old/linux/drivers/net/at1700.c new/linux/drivers/net/at1700.c --- old/linux/drivers/net/at1700.c Sun Nov 30 21:21:45 1997 +++ new/linux/drivers/net/at1700.c Tue Feb 10 21:56:44 1998 @@ -424,7 +424,7 @@ /* Turn on Tx interrupts back on. */ outb(0x82, ioaddr + TX_INTR); } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } diff -ur --new-file old/linux/drivers/net/atari_bionet.c new/linux/drivers/net/atari_bionet.c --- old/linux/drivers/net/atari_bionet.c Thu Apr 24 04:01:18 1997 +++ new/linux/drivers/net/atari_bionet.c Tue Feb 10 21:56:44 1998 @@ -465,7 +465,7 @@ lp->stats.tx_packets++; lp->stats.tx_bytes+=length; } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } diff -ur --new-file old/linux/drivers/net/atari_pamsnet.c new/linux/drivers/net/atari_pamsnet.c --- old/linux/drivers/net/atari_pamsnet.c Thu Apr 24 04:01:18 1997 +++ new/linux/drivers/net/atari_pamsnet.c Tue Feb 10 21:56:44 1998 @@ -730,7 +730,7 @@ lp->stats.tx_packets++; lp->stats.tx_bytes+=length; } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } diff -ur --new-file old/linux/drivers/net/atarilance.c new/linux/drivers/net/atarilance.c --- old/linux/drivers/net/atarilance.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/atarilance.c Sat Feb 21 02:55:45 1998 @@ -817,8 +817,9 @@ head->misc = 0; lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len ); head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP; - dev_kfree_skb( skb, FREE_WRITE ); + dev_kfree_skb( skb ); lp->cur_tx++; + lp->stats.tx_bytes += skb->len; while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) { lp->cur_tx -= TX_RING_SIZE; lp->dirty_tx -= TX_RING_SIZE; @@ -1027,6 +1028,7 @@ skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); lp->stats.rx_packets++; + lp->stats.rx_bytes += skb->len; } } diff -ur --new-file old/linux/drivers/net/atp.c new/linux/drivers/net/atp.c --- old/linux/drivers/net/atp.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/atp.c Tue Feb 10 21:56:44 1998 @@ -467,7 +467,7 @@ write_reg_high(ioaddr, IMR, ISRh_RxErr); } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } diff -ur --new-file old/linux/drivers/net/com20020.c new/linux/drivers/net/com20020.c --- old/linux/drivers/net/com20020.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/com20020.c Sat Feb 21 03:28:22 1998 @@ -28,7 +28,6 @@ #include -#include #include #include @@ -720,7 +719,7 @@ if (out->skb) { lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb,FREE_WRITE); + dev_kfree_skb(out->skb); } out->skb=NULL; diff -ur --new-file old/linux/drivers/net/com90io.c new/linux/drivers/net/com90io.c --- old/linux/drivers/net/com90io.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/com90io.c Sat Feb 21 03:28:22 1998 @@ -28,7 +28,6 @@ #include -#include #include #include @@ -611,7 +610,7 @@ if (out->skb) { lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb,FREE_WRITE); + dev_kfree_skb(out->skb); } out->skb=NULL; diff -ur --new-file old/linux/drivers/net/com90xx.c new/linux/drivers/net/com90xx.c --- old/linux/drivers/net/com90xx.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/com90xx.c Sat Feb 21 03:28:22 1998 @@ -26,7 +26,6 @@ #include -#include #include #include @@ -886,7 +885,7 @@ if (out->skb) { lp->stats.tx_bytes += out->skb->len; - dev_kfree_skb(out->skb,FREE_WRITE); + dev_kfree_skb(out->skb); } out->skb=NULL; diff -ur --new-file old/linux/drivers/net/cops.c new/linux/drivers/net/cops.c --- old/linux/drivers/net/cops.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/cops.c Mon Mar 2 20:55:41 1998 @@ -47,7 +47,6 @@ #include #endif -#include #include #include #include @@ -114,8 +113,8 @@ * the same and just have different names or only have minor differences * such as more IO ports. As this driver is tested it will * become more clear on exactly what cards are supported. The driver - * defaults to using Dayna mode. To change the drivers mode adjust - * drivers/net/CONFIG, and the line COPS_OPTS = -DDAYNA to -DTANGENT. + * defaults to using Dayna mode. To change the drivers mode, simply + * select Dayna or Tangent mode when configuring the kernel. * * This driver should support: * TANGENT driver mode: @@ -747,7 +746,7 @@ { printk(KERN_NOTICE "%s: Bad packet length of %d bytes.\n", dev->name, pkt_len); lp->stats.tx_errors++; - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return; } @@ -755,7 +754,7 @@ if(rsp_type == LAP_INIT_RSP) { lp->node_acquire = skb->data[0]; /* Nodeid taken from received packet. */ - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return; } @@ -764,7 +763,7 @@ { printk("%s: Bad packet type %d.\n", dev->name, rsp_type); lp->stats.tx_errors++; - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return; } @@ -856,7 +855,7 @@ dev->trans_start = jiffies; } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); dev->tbusy = 0; return 0; diff -ur --new-file old/linux/drivers/net/cs89x0.c new/linux/drivers/net/cs89x0.c --- old/linux/drivers/net/cs89x0.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/cs89x0.c Sat Feb 21 03:28:22 1998 @@ -44,7 +44,6 @@ /* Always include 'config.h' first in case the user wants to turn on or override something. */ -#include #ifdef MODULE #include #include @@ -782,7 +781,7 @@ restore_flags(flags); dev->trans_start = jiffies; } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } @@ -1078,11 +1077,11 @@ if (dev_cs89x0.priv != NULL) { /* Free up the private structure, or leak memory :-) */ + unregister_netdev(&dev_cs89x0); kfree(dev_cs89x0.priv); dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ /* If we don't do this, we can't re-insmod it later. */ release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT); - unregister_netdev(&dev_cs89x0); } } #endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/de4x5.c new/linux/drivers/net/de4x5.c --- old/linux/drivers/net/de4x5.c Sat Jan 10 19:46:51 1998 +++ new/linux/drivers/net/de4x5.c Wed Mar 18 06:15:40 1998 @@ -213,8 +213,8 @@ insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'. - For a compiled in driver, in linux/drivers/net/CONFIG, place e.g. - DE4X5_OPTS = -DDE4X5_PARM='"eth0:fdx autosense=AUI eth2:autosense=TP"' + For a compiled in driver, at or above line 526, place e.g. + #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP" Yes, I know full duplex isn't permissible on BNC or AUI; they're just examples. By default, full duplex is turned off and AUTO is the default @@ -369,11 +369,16 @@ Fix bug in pci_probe() for 64 bit systems reported by . 0.533 9-Jan-98 Fix more 64 bit bugs reported by . + 0.534 24-Jan-98 Fix last (?) endian bug from + + 0.535 21-Feb-98 Fix Ethernet Address PROM reset bug for DC21040. + 0.536 21-Mar-98 Change pci_probe() to use the pci_dev structure. + **Incompatible with 2.0.x from here.** ========================================================================= */ -static const char *version = "de4x5.c:V0.533 1998/1/9 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.536 1998/3/5 davies@maniac.ultranet.com\n"; #include @@ -388,11 +393,15 @@ #include #include #include +#include +#include + #include #include #include #include #include +#include #include #include @@ -406,31 +415,6 @@ #include "de4x5.h" #define c_char const char - -#include -#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0) -# define __initfunc(__arginit) __arginit -# define test_and_set_bit set_bit -# define net_device_stats enet_statistics -# define copy_to_user(a,b,c) memcpy_tofs(a,b,c) -# define copy_from_user(a,b,c) memcpy_fromfs(a,b,c) -# define le16_to_cpu(a) cpu_to_le16(a) -# define le32_to_cpu(a) cpu_to_le32(a) -# ifdef __powerpc__ -# define cpu_to_le16(a) ((((a) & 0x00ffU) << 8) | (((a) & 0xff00U) >> 8)) -# define cpu_to_le32(a) ((((a) & 0x000000ffU) << 24) |\ - (((a) & 0x0000ff00U) << 8) |\ - (((a) & 0x00ff0000U) >> 8) |\ - (((a) & 0xff000000U) >> 24)) -# else -# define cpu_to_le16(a) (a) -# define cpu_to_le32(a) (a) -# endif /* __powerpc__ */ -# include -#else -# include -# include -#endif /* LINUX_VERSION_CODE */ #define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a))) /* @@ -536,8 +520,8 @@ ** insmod de4x5 args='eth1:fdx autosense=BNC eth0:autosense=100Mb'. ** ** For a compiled in driver, place e.g. -** DE4X5_OPTS = -DDE4X5_PARM='"eth0:fdx autosense=AUI eth2:autosense=TP"' -** in linux/drivers/net/CONFIG +** #define DE4X5_PARM "eth0:fdx autosense=AUI eth2:autosense=TP" +** here */ #ifdef DE4X5_PARM static char *args = DE4X5_PARM; @@ -590,6 +574,12 @@ #define DE4X5_NAME_LENGTH 8 /* +** Ethernet PROM defines for DC21040 +*/ +#define PROBE_LENGTH 32 +#define ETH_PROM_SIG 0xAA5500FFUL + +/* ** PCI Bus defines */ #define PCI_MAX_BUS_NUM 8 @@ -910,6 +900,7 @@ static int EISA_signature(char *name, s32 eisa_id); static int PCI_signature(char *name, struct bus_type *lp); static void DevicePresent(u_long iobase); +static void enet_addr_rst(u_long aprom_addr); static int de4x5_bad_srom(struct bus_type *lp); static short srom_rd(u_long address, u_char offset); static void srom_latch(u_int command, u_long address); @@ -979,11 +970,9 @@ int (*init)(struct device *)); static int count_adapters(void); static int loading_module = 1; -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) MODULE_PARM(de4x5_debug, "i"); MODULE_PARM(dec_only, "i"); MODULE_PARM(args, "s"); -#endif /* LINUX_VERSION_CODE */ # else static int loading_module = 0; #endif /* MODULE */ @@ -1505,9 +1494,7 @@ cli(); test_and_set_bit(0, (void*)&dev->tbusy); load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); -#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) lp->stats.tx_bytes += skb->len; -#endif outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */ lp->tx_new = (++lp->tx_new) % lp->txRingSize; @@ -1557,9 +1544,7 @@ printk("%s: Re-entering the interrupt handler.\n", dev->name); DISABLE_IRQs; /* Ensure non re-entrancy */ -#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) synchronize_irq(); -#endif dev->interrupt = MASK_INTERRUPTS; for (limit=0; limit<8; limit++) { @@ -1657,9 +1642,7 @@ /* Update stats */ lp->stats.rx_packets++; -#if LINUX_VERSION_CODE >= ((2 << 16) | (1 << 8)) lp->stats.rx_bytes += pkt_len; -#endif de4x5_local_stats(dev, skb->data, pkt_len); } } @@ -1719,7 +1702,7 @@ /* Free the buffer. */ if (lp->tx_skb[entry] != NULL) { - dev_kfree_skb(lp->tx_skb[entry], FREE_WRITE); + dev_kfree_skb(lp->tx_skb[entry]); lp->tx_skb[entry] = NULL; } } @@ -2040,7 +2023,7 @@ outl(0x00006000, PCI_CFLT); outl(iobase, PCI_CBIO); - DevicePresent(DE4X5_APROM); + DevicePresent(EISA_APROM); if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) { dev->irq = irq; if ((status = de4x5_hw_init(dev, iobase)) == 0) { @@ -2080,10 +2063,11 @@ pci_probe(struct device *dev, u_long ioaddr)) { u_char pb, pbus, dev_num, dnum, dev_fn, timer; - u_short dev_id, vendor, index, status; - u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE; + u_short vendor, index, status; + u_int irq = 0, device, class = DE4X5_CLASS_CODE; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ struct bus_type *lp = &bus; + struct pci_dev *pdev; if (lastPCI == NO_MORE_PCI) return; @@ -2107,96 +2091,77 @@ (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); index++) { dev_num = PCI_SLOT(dev_fn); - if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) { -#ifdef __sparc_v9__ - struct pci_dev *pdev; - for (pdev = pci_devices; pdev; pdev = pdev->next) { - if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break; - } -#endif - device = 0; - pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); - device = dev_id; - device <<= 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { - continue; - } - - /* Search for an SROM on this bus */ - if (lp->bus_num != pb) { - lp->bus_num = pb; - srom_search(index); - } + if ((pbus || dnum) && ((pbus != pb) || (dnum != dev_num))) continue; + for (pdev = pci_devices; pdev; pdev = pdev->next) { + if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break; + } - /* Get the chip configuration revision register */ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + vendor = pdev->vendor; + device = pdev->device << 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; - /* Set the device number information */ - lp->device = dev_num; + /* Search for an SROM on this bus */ + if (lp->bus_num != pb) { lp->bus_num = pb; + srom_search(index); + } + + /* Get the chip configuration revision register */ + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + + /* Set the device number information */ + lp->device = dev_num; + lp->bus_num = pb; - /* Set the chipset information */ - if (is_DC2114x) device |= (cfrv & CFRV_RN); - lp->chipset = device; + /* Set the chipset information */ + if (is_DC2114x) device |= (cfrv & CFRV_RN); + lp->chipset = device; - /* Get the board I/O address (64 bits on sparc64) */ -#ifndef __sparc_v9__ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); - iobase = tmp; -#else - iobase = pdev->base_address[0]; -#endif - iobase &= CBIO_MASK; + /* Get the board I/O address (64 bits on sparc64) */ + iobase = pdev->base_address[0] & CBIO_MASK; - /* Fetch the IRQ to be used */ -#ifndef __sparc_v9__ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, - (char *)&irq); -#else - irq = pdev->irq; -#endif - if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; + /* Fetch the IRQ to be used */ + irq = pdev->irq; + if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; - /* Check if I/O accesses and Bus Mastering are enabled */ - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + /* Check if I/O accesses and Bus Mastering are enabled */ + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); #ifdef __powerpc__ - if (!(status & PCI_COMMAND_IO)) { - status |= PCI_COMMAND_IO; - pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - } + if (!(status & PCI_COMMAND_IO)) { + status |= PCI_COMMAND_IO; + pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + } #endif /* __powerpc__ */ - if (!(status & PCI_COMMAND_IO)) continue; + if (!(status & PCI_COMMAND_IO)) continue; - if (!(status & PCI_COMMAND_MASTER)) { - status |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); - } - if (!(status & PCI_COMMAND_MASTER)) continue; + if (!(status & PCI_COMMAND_MASTER)) { + status |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); + pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); + } + if (!(status & PCI_COMMAND_MASTER)) continue; - /* Check the latency timer for values > 0x60 */ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer); - if (timer < 0x60) { - pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60); - } + /* Check the latency timer for values >= 0x60 */ + pcibios_read_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, &timer); + if (timer < 0x60) { + pcibios_write_config_byte(pb, PCI_DEVICE, PCI_LATENCY_TIMER, 0x60); + } - DevicePresent(DE4X5_APROM); - if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { - dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { - num_de4x5s++; - if (loading_module) { - link_modules(lastModule, dev); - lastPCI = index; - } - return; + DevicePresent(DE4X5_APROM); + if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { + dev->irq = irq; + if ((status = de4x5_hw_init(dev, iobase)) == 0) { + num_de4x5s++; + if (loading_module) { + link_modules(lastModule, dev); + lastPCI = index; } - } else if (ioaddr != 0) { - printk("%s: region already allocated at 0x%04lx.\n", dev->name, - iobase); + return; } + } else if (ioaddr != 0) { + printk("%s: region already allocated at 0x%04lx.\n", dev->name, + iobase); } } @@ -2215,11 +2180,12 @@ srom_search(int index)) { u_char pb, dev_fn; - u_short dev_id, dev_num, vendor, status; - u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE; + u_short dev_num, vendor, status; + u_int irq = 0, device, class = DE4X5_CLASS_CODE; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j; struct bus_type *lp = &bus; + struct pci_dev *pdev; for (; (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); @@ -2227,20 +2193,13 @@ if (lp->bus_num != pb) return; dev_num = PCI_SLOT(dev_fn); -#ifdef __sparc_v9__ - struct pci_dev *pdev; for (pdev = pci_devices; pdev; pdev = pdev->next) { if ((pdev->bus->number == pb) && (pdev->devfn == dev_fn)) break; } -#endif - device = 0; - pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &dev_id); - device = dev_id; - device <<= 8; - if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) { - continue; - } + + vendor = pdev->vendor; + device = pdev->device << 8; + if (!(is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x)) continue; /* Get the chip configuration revision register */ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); @@ -2254,21 +2213,10 @@ lp->chipset = device; /* Get the board I/O address (64 bits on sparc64) */ -#ifndef __sparc_v9__ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); - iobase = tmp; -#else - iobase = pdev->base_address[0]; -#endif - iobase &= CBIO_MASK; + iobase = pdev->base_address[0] & CBIO_MASK; /* Fetch the IRQ to be used */ -#ifndef __sparc_v9__ - pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, - (char *)&irq); -#else irq = pdev->irq; -#endif if ((irq == 0) || (irq == 0xff) || ((int)irq == -1)) continue; /* Check if I/O accesses are enabled */ @@ -3592,7 +3540,7 @@ for (i=0; irxRingSize; i++) { if ((u_long) lp->rx_skb[i] > 1) { - dev_kfree_skb(lp->rx_skb[i], FREE_WRITE); + dev_kfree_skb(lp->rx_skb[i]); } lp->rx_ring[i].status = 0; lp->rx_skb[i] = (struct sk_buff *)1; /* Dummy entry */ @@ -3609,7 +3557,7 @@ for (i=0; itxRingSize; i++) { if (lp->tx_skb[i]) { - dev_kfree_skb(lp->tx_skb[i], FREE_WRITE); + dev_kfree_skb(lp->tx_skb[i]); lp->tx_skb[i] = NULL; } lp->tx_ring[i].status = 0; @@ -3617,7 +3565,7 @@ /* Unload the locally queued packets */ while (lp->cache.skb) { - dev_kfree_skb(de4x5_get_cache(dev), FREE_WRITE); + dev_kfree_skb(de4x5_get_cache(dev)); } return; @@ -3980,7 +3928,11 @@ struct bus_type *lp = &bus; if (lp->chipset == DC21040) { - outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */ + if (lp->bus == EISA) { + enet_addr_rst(aprom_addr); /* Reset Ethernet Address ROM Pointer */ + } else { + outl(0, aprom_addr); /* Reset Ethernet Address ROM Pointer */ + } } else { /* Read new srom */ u_short tmp, *p = (short *)((char *)&lp->srom + SROM_HWADD); for (i=0; i<(ETH_ALEN>>1); i++) { @@ -4004,6 +3956,45 @@ } /* +** Since the write on the Enet PROM register doesn't seem to reset the PROM +** pointer correctly (at least on my DE425 EISA card), this routine should do +** it...from depca.c. +*/ +static void +enet_addr_rst(u_long aprom_addr) +{ + union { + struct { + u32 a; + u32 b; + } llsig; + char Sig[sizeof(u32) << 1]; + } dev; + short sigLength=0; + s8 data; + int i, j; + + dev.llsig.a = ETH_PROM_SIG; + dev.llsig.b = ETH_PROM_SIG; + sigLength = sizeof(u32) << 1; + + for (i=0,j=0;j= LinuxVersionCode(2,1,0) MODULE_PARM(io, "i"); -#endif /* LINUX_VERSION_CODE */ int init_module(void) @@ -5728,16 +5717,18 @@ static int count_adapters(void) { - int i, j; + int i, j=0; char name[DE4X5_STRLEN]; - u_char pb, dev_fn, dev_num; - u_short dev_id, vendor; + u_char pb, dev_fn; + u_short vendor; u_int class = DE4X5_CLASS_CODE; u_int device; + struct pci_dev *pdev; + #ifndef __sparc_v9__ u_long iobase = 0x1000; - for (j=0, i=1; inext) { + if ((pdev->bus->number==pb) && (pdev->devfn==dev_fn)) break; + } + + vendor = pdev->vendor; + device = pdev->device << 8; if (is_DC21040 || is_DC21041 || is_DC21140 || is_DC2114x) j++; } diff -ur --new-file old/linux/drivers/net/de600.c new/linux/drivers/net/de600.c --- old/linux/drivers/net/de600.c Sun Nov 30 21:21:45 1997 +++ new/linux/drivers/net/de600.c Tue Feb 10 21:56:44 1998 @@ -471,7 +471,7 @@ skb->sk->prot->rspace = de600_rspace; /* Ugh! */ #endif - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } diff -ur --new-file old/linux/drivers/net/de620.c new/linux/drivers/net/de620.c --- old/linux/drivers/net/de620.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/de620.c Mon Mar 2 20:55:41 1998 @@ -100,7 +100,6 @@ /* * Enable debugging by "-DDE620_DEBUG=3" when compiling, - * OR in "./CONFIG" * OR by enabling the following #define * * use 0 for production, 1 for verification, >2 for debug @@ -580,7 +579,7 @@ restore_flags(flags); /* interrupts maybe back on */ - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } diff -ur --new-file old/linux/drivers/net/defxx.c new/linux/drivers/net/defxx.c --- old/linux/drivers/net/defxx.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/defxx.c Tue Feb 10 21:56:44 1998 @@ -3209,7 +3209,7 @@ dev->name, skb->len); bp->xmt_length_errors++; /* bump error counter */ mark_bh(NET_BH); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return(0); /* return "success" */ } /* @@ -3231,7 +3231,7 @@ else { bp->xmt_discards++; /* bump error counter */ - dev_kfree_skb(skb, FREE_WRITE); /* free sk_buff now */ + dev_kfree_skb(skb); /* free sk_buff now */ return(0); /* return "success" */ } } @@ -3381,7 +3381,7 @@ /* Return skb to operating system */ - dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE); + dev_kfree_skb(p_xmt_drv_descr->p_skb); /* Increment transmit counters */ @@ -3458,7 +3458,7 @@ /* Return skb to operating system */ - dev_kfree_skb(p_xmt_drv_descr->p_skb, FREE_WRITE); + dev_kfree_skb(p_xmt_drv_descr->p_skb); /* Increment transmit error counter */ diff -ur --new-file old/linux/drivers/net/depca.c new/linux/drivers/net/depca.c --- old/linux/drivers/net/depca.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/depca.c Tue Feb 10 21:56:44 1998 @@ -818,7 +818,7 @@ outw(INEA | TDMD, DEPCA_DATA); dev->trans_start = jiffies; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } if (TX_BUFFS_AVAIL) { dev->tbusy = 0; diff -ur --new-file old/linux/drivers/net/dgrs.c new/linux/drivers/net/dgrs.c --- old/linux/drivers/net/dgrs.c Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/net/dgrs.c Wed Feb 25 07:08:01 1998 @@ -21,7 +21,7 @@ * When compiled as a loadable module, this driver can operate * the board as either a 4/6 port switch with a 5th or 7th port * that is a conventional NIC interface as far as the host is - * concerned, OR as 4/6 independant NICs. To select multi-NIC + * concerned, OR as 4/6 independent NICs. To select multi-NIC * mode, add "nicmode=1" on the insmod load line for the driver. * * This driver uses the "dev" common ethernet device structure @@ -776,7 +776,7 @@ ++privN->stats.tx_packets; - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return (0); no_resources: @@ -1250,12 +1250,12 @@ )) { DGRS_PRIV *priv; - int i; #ifdef MODULE { /* Allocate and fill new device structure. */ int dev_size = sizeof(struct device) + sizeof(DGRS_PRIV); + int i; dev = (struct device *) kmalloc(dev_size, GFP_KERNEL); memset(dev, 0, dev_size); @@ -1358,6 +1358,8 @@ /* * Scan for all boards */ +static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 }; + __initfunc(static int dgrs_scan(struct device *dev)) { @@ -1463,8 +1465,6 @@ */ if (EISA_bus) { - static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 }; - for (io = 0x1000; io < 0x9000; io += 0x1000) { if (inb(io+ES4H_MANUFmsb) != 0x10 diff -ur --new-file old/linux/drivers/net/dlci.c new/linux/drivers/net/dlci.c --- old/linux/drivers/net/dlci.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/dlci.c Sat Feb 21 03:28:22 1998 @@ -28,6 +28,7 @@ * 2 of the License, or (at your option) any later version. */ +#include /* for CONFIG_DLCI_COUNT */ #include #include @@ -230,7 +231,7 @@ dlp->stats.rx_packets++; } else - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } static int dlci_transmit(struct sk_buff *skb, struct device *dev) @@ -275,7 +276,7 @@ /* experience suggest a slightly more conservative approach */ if (!ret) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); dev->tbusy = 0; } diff -ur --new-file old/linux/drivers/net/dummy.c new/linux/drivers/net/dummy.c --- old/linux/drivers/net/dummy.c Tue Jan 13 00:28:18 1998 +++ new/linux/drivers/net/dummy.c Tue Feb 10 21:56:44 1998 @@ -110,7 +110,7 @@ static int dummy_xmit(struct sk_buff *skb, struct device *dev) { struct net_device_stats *stats; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); stats = (struct net_device_stats *)dev->priv; stats->tx_packets++; diff -ur --new-file old/linux/drivers/net/e2100.c new/linux/drivers/net/e2100.c --- old/linux/drivers/net/e2100.c Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/net/e2100.c Thu Feb 19 23:58:40 1998 @@ -441,10 +441,10 @@ struct device *dev = &dev_e21[this_dev]; if (dev->priv != NULL) { /* NB: e21_close() handles free_irq */ + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, E21_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/eepro.c new/linux/drivers/net/eepro.c --- old/linux/drivers/net/eepro.c Sun Nov 30 21:21:45 1997 +++ new/linux/drivers/net/eepro.c Tue Feb 10 21:56:44 1998 @@ -720,7 +720,7 @@ dev->trans_start = jiffies; } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ /* lp->stats.tx_aborted_errors++; */ diff -ur --new-file old/linux/drivers/net/eepro100.c new/linux/drivers/net/eepro100.c --- old/linux/drivers/net/eepro100.c Tue Dec 30 23:19:39 1997 +++ new/linux/drivers/net/eepro100.c Mon Mar 16 23:17:29 1998 @@ -38,7 +38,6 @@ /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 200; -#include #ifdef MODULE #ifdef MODVERSIONS #include @@ -1186,7 +1185,7 @@ /* Free the original skb. */ if (sp->tx_skbuff[entry]) { sp->stats.tx_packets++; /* Count only user packets. */ - dev_kfree_skb(sp->tx_skbuff[entry], FREE_WRITE); + dev_kfree_skb(sp->tx_skbuff[entry]); sp->tx_skbuff[entry] = 0; } dirty_tx++; @@ -1349,7 +1348,7 @@ #if (LINUX_VERSION_CODE >= VERSION(1,3,44)) if (! rx_in_place) { skb_reserve(skb, 2); /* 16 byte align the data fields */ -#if defined(__i386) && notyet +#if defined(__i386__) && notyet /* Packet is in one chunk -- we can copy + cksum. */ eth_io_copy_and_sum(skb, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len, 0); @@ -1426,7 +1425,7 @@ sp->rx_skbuff[i] = 0; /* Clear the Rx descriptors. */ if (skb) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } for (i = 0; i < TX_RING_SIZE; i++) { @@ -1434,7 +1433,7 @@ sp->tx_skbuff[i] = 0; /* Clear the Tx descriptors. */ if (skb) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } if (sp->mc_setup_frm) { kfree(sp->mc_setup_frm); diff -ur --new-file old/linux/drivers/net/eexpress.c new/linux/drivers/net/eexpress.c --- old/linux/drivers/net/eexpress.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/eexpress.c Thu Feb 19 23:58:40 1998 @@ -537,7 +537,7 @@ eexp_hw_tx_pio(dev,data,length); } - dev_kfree_skb(buf, FREE_WRITE); + dev_kfree_skb(buf); outb(SIRQ_en|irqrmap[dev->irq],dev->base_addr+SET_IRQ); return 0; } @@ -1558,10 +1558,10 @@ for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) { struct device *dev = &dev_eexp[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(dev->base_addr, EEXP_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/eql.c new/linux/drivers/net/eql.c --- old/linux/drivers/net/eql.c Tue Dec 9 18:49:58 1997 +++ new/linux/drivers/net/eql.c Tue Feb 10 21:56:44 1998 @@ -387,7 +387,7 @@ */ eql->stats->tx_dropped++; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } return 0; } diff -ur --new-file old/linux/drivers/net/es3210.c new/linux/drivers/net/es3210.c --- old/linux/drivers/net/es3210.c Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/net/es3210.c Thu Feb 19 23:58:40 1998 @@ -430,11 +430,11 @@ for (this_dev = 0; this_dev < MAX_ES_CARDS; this_dev++) { struct device *dev = &dev_es3210[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; free_irq(dev->irq, dev); release_region(dev->base_addr, ES_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/eth16i.c new/linux/drivers/net/eth16i.c --- old/linux/drivers/net/eth16i.c Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/net/eth16i.c Tue Feb 10 21:56:44 1998 @@ -977,7 +977,7 @@ /* Turn TX interrupts back on */ /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */ } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } diff -ur --new-file old/linux/drivers/net/ethertap.c new/linux/drivers/net/ethertap.c --- old/linux/drivers/net/ethertap.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/ethertap.c Sun Mar 1 23:40:39 1998 @@ -11,6 +11,7 @@ * even for building bridging tunnels. */ +#include #include #include @@ -25,6 +26,7 @@ #include #include +#include #include /* @@ -36,7 +38,10 @@ static int ethertap_start_xmit(struct sk_buff *skb, struct device *dev); static int ethertap_close(struct device *dev); static struct net_device_stats *ethertap_get_stats(struct device *dev); -static int ethertap_rx(int id, struct sk_buff *skb); +static void ethertap_rx(struct sock *sk, int len); +#ifdef CONFIG_ETHERTAP_MC +static void set_multicast_list(struct device *dev); +#endif static int ethertap_debug = 0; @@ -48,6 +53,10 @@ struct net_local { + struct sock *nl; +#ifdef CONFIG_ETHERTAP_MC + __u32 groups; +#endif struct net_device_stats stats; }; @@ -58,7 +67,7 @@ __initfunc(int ethertap_probe(struct device *dev)) { - memcpy(dev->dev_addr, "\xFD\xFD\x00\x00\x00\x00", 6); + memcpy(dev->dev_addr, "\xFE\xFD\x00\x00\x00\x00", 6); if (dev->mem_start & 0xf) ethertap_debug = dev->mem_start & 0x7; @@ -79,6 +88,9 @@ dev->hard_start_xmit = ethertap_start_xmit; dev->stop = ethertap_close; dev->get_stats = ethertap_get_stats; +#ifdef CONFIG_ETHERTAP_MC + dev->set_multicast_list = set_multicast_list; +#endif /* * Setup the generic properties @@ -86,10 +98,10 @@ ether_setup(dev); - dev->flags|=IFF_NOARP; /* Need to set ARP - looks like there is a bug - in the 2.1.x hard header code currently */ + dev->tx_queue_len = 0; + dev->flags|=IFF_NOARP; tap_map[dev->base_addr]=dev; - + return 0; } @@ -99,28 +111,58 @@ static int ethertap_open(struct device *dev) { - struct in_device *in_dev; + struct net_local *lp = (struct net_local*)dev->priv; + if (ethertap_debug > 2) printk("%s: Doing ethertap_open()...", dev->name); - netlink_attach(dev->base_addr, ethertap_rx); + + MOD_INC_USE_COUNT; + + lp->nl = netlink_kernel_create(dev->base_addr, ethertap_rx); + if (lp->nl == NULL) { + MOD_DEC_USE_COUNT; + return -ENOBUFS; + } + dev->start = 1; dev->tbusy = 0; + return 0; +} - /* Fill in the MAC based on the IP address. We do the same thing - here as PLIP does */ - - if((in_dev=dev->ip_ptr)!=NULL) - { - /* - * Any address wil do - we take the first - */ - struct in_ifaddr *ifa=in_dev->ifa_list; - if(ifa!=NULL) - memcpy(dev->dev_addr+2,&ifa->ifa_local,4); +#ifdef CONFIG_ETHERTAP_MC +static unsigned ethertap_mc_hash(__u8 *dest) +{ + unsigned idx = 0; + idx ^= dest[0]; + idx ^= dest[1]; + idx ^= dest[2]; + idx ^= dest[3]; + idx ^= dest[4]; + idx ^= dest[5]; + return 1U << (idx&0x1F); +} + +static void set_multicast_list(struct device *dev) +{ + unsigned groups = ~0; + struct net_local *lp = (struct net_local *)dev->priv; + + if (!(dev->flags&(IFF_NOARP|IFF_PROMISC|IFF_ALLMULTI))) { + struct dev_mc_list *dmi; + + groups = ethertap_mc_hash(dev->broadcast); + + for (dmi=dev->mc_list; dmi; dmi=dmi->next) { + if (dmi->dmi_addrlen != 6) + continue; + groups |= ethertap_mc_hash(dmi->dmi_addr); + } } - MOD_INC_USE_COUNT; - return 0; + lp->groups = groups; + if (lp->nl) + lp->nl->protinfo.af_netlink.groups = groups; } +#endif /* * We transmit by throwing the packet at netlink. We have to clone @@ -130,20 +172,110 @@ static int ethertap_start_xmit(struct sk_buff *skb, struct device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - struct sk_buff *tmp; - /* copy buffer to tap */ - tmp=skb_clone(skb, GFP_ATOMIC); - if(tmp) - { - if(netlink_post(dev->base_addr, tmp)<0) - kfree_skb(tmp, FREE_WRITE); - lp->stats.tx_bytes+=skb->len; - lp->stats.tx_packets++; +#ifdef CONFIG_ETHERTAP_MC + struct ethhdr *eth = (struct ethhdr*)skb->data; +#endif + + if (skb_headroom(skb) < 2) { + printk(KERN_DEBUG "%s : bug --- xmit with head<2\n", dev->name); + dev_kfree_skb(skb); + return 0; + } + skb_push(skb, 2); + + /* Make the same thing, which loopback does. */ + if (skb_shared(skb)) { + struct sk_buff *skb2 = skb; + skb = skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */ + if (skb==NULL) { + dev_kfree_skb(skb2); + return 0; + } + dev_kfree_skb(skb2); + } + /* ... but do not orphan it here, netlink does it in any case. */ + + lp->stats.tx_bytes+=skb->len; + lp->stats.tx_packets++; + +#ifndef CONFIG_ETHERTAP_MC + netlink_broadcast(lp->nl, skb, 0, ~0, GFP_ATOMIC); +#else + if (dev->flags&IFF_NOARP) { + netlink_broadcast(lp->nl, skb, 0, ~0, GFP_ATOMIC); + return 0; } - dev_kfree_skb (skb, FREE_WRITE); + + if (!(eth->h_dest[0]&1)) { + /* Unicast packet */ + __u32 pid; + memcpy(&pid, eth->h_dest+2, 4); + netlink_unicast(lp->nl, skb, ntohl(pid), MSG_DONTWAIT); + } else + netlink_broadcast(lp->nl, skb, 0, ethertap_mc_hash(eth->h_dest), GFP_ATOMIC); +#endif return 0; } +static __inline__ int ethertap_rx_skb(struct sk_buff *skb, struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; +#ifdef CONFIG_ETHERTAP_MC + struct ethhdr *eth = (struct ethhdr*)(skb->data + 2); +#endif + int len = skb->len; + + if (len < 16) { + printk(KERN_DEBUG "%s : rx len = %d\n", dev->name, len); + kfree_skb(skb); + return -EINVAL; + } + if (NETLINK_CREDS(skb)->uid) { + printk(KERN_INFO "%s : user %d\n", dev->name, NETLINK_CREDS(skb)->uid); + kfree_skb(skb); + return -EPERM; + } + +#ifdef CONFIG_ETHERTAP_MC + if (!(dev->flags&(IFF_NOARP|IFF_PROMISC))) { + int drop = 0; + + if (eth->h_dest[0]&1) { + if (!(ethertap_mc_hash(eth->h_dest)&lp->groups)) + drop = 1; + } else if (memcmp(eth->h_dest, dev->dev_addr, 6) != 0) + drop = 1; + + if (drop) { + if (ethertap_debug > 3) + printk(KERN_DEBUG "%s : not for us\n", dev->name); + kfree_skb(skb); + return -EINVAL; + } + } +#endif + + if (skb_shared(skb)) { + struct sk_buff *skb2 = skb; + skb = skb_clone(skb, GFP_KERNEL); /* Clone the buffer */ + if (skb==NULL) { + kfree_skb(skb2); + return -ENOBUFS; + } + kfree_skb(skb2); + } else + skb_orphan(skb); + + skb_pull(skb, 2); + skb->dev = dev; + skb->protocol=eth_type_trans(skb,dev); + memset(skb->cb, 0, sizeof(skb->cb)); + lp->stats.rx_packets++; + lp->stats.rx_bytes+=len; + netif_rx(skb); + return len; +} + /* * The typical workload of the driver: * Handle the ether interface interrupts. @@ -151,37 +283,40 @@ * (In this case handle the packets posted from user space..) */ -static int ethertap_rx(int id, struct sk_buff *skb) +static void ethertap_rx(struct sock *sk, int len) { - struct device *dev = (struct device *)(tap_map[id]); - struct net_local *lp; - int len=skb->len; - - if(dev==NULL) - { - printk("ethertap: bad unit!\n"); - kfree_skb(skb, FREE_WRITE); - return -ENXIO; + struct device *dev = tap_map[sk->protocol]; + struct sk_buff *skb; + + if (dev==NULL) { + printk(KERN_CRIT "ethertap: bad unit!\n"); + skb_queue_purge(&sk->receive_queue); + return; } - lp = (struct net_local *)dev->priv; if (ethertap_debug > 3) printk("%s: ethertap_rx()\n", dev->name); - skb->dev = dev; - skb->protocol=eth_type_trans(skb,dev); - lp->stats.rx_packets++; - lp->stats.rx_bytes+=len; - netif_rx(skb); - return len; + + while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) + ethertap_rx_skb(skb, dev); } static int ethertap_close(struct device *dev) { + struct net_local *lp = (struct net_local *)dev->priv; + struct sock *sk = lp->nl; + if (ethertap_debug > 2) - printk("%s: Shutting down tap %ld.\n", dev->name, dev->base_addr); + printk("%s: Shutting down.\n", dev->name); dev->tbusy = 1; dev->start = 0; + + if (sk) { + lp->nl = NULL; + sock_release(sk->socket); + } + MOD_DEC_USE_COUNT; return 0; } @@ -213,7 +348,7 @@ sprintf(devicename,"tap%d",unit); if (dev_get(devicename)) { - printk(KERN_INFO "ethertap: tap %d already loaded.\n", unit); + printk(KERN_INFO "%s already loaded.\n", devicename); return -EBUSY; } if (register_netdev(&dev_ethertap) != 0) diff -ur --new-file old/linux/drivers/net/ewrk3.c new/linux/drivers/net/ewrk3.c --- old/linux/drivers/net/ewrk3.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/ewrk3.c Thu Feb 19 23:58:40 1998 @@ -847,7 +847,7 @@ } dev->trans_start = jiffies; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } else { /* return unused page to the free memory queue */ outb(page, EWRK3_FMQ); @@ -1904,13 +1904,13 @@ void cleanup_module(void) { + unregister_netdev(&thisEthwrk); if (thisEthwrk.priv) { kfree(thisEthwrk.priv); thisEthwrk.priv = NULL; } thisEthwrk.irq = 0; - unregister_netdev(&thisEthwrk); release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE); } #endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/fmv18x.c new/linux/drivers/net/fmv18x.c --- old/linux/drivers/net/fmv18x.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/fmv18x.c Tue Feb 10 21:56:44 1998 @@ -388,7 +388,7 @@ /* Re-enable interrupts */ outw(0x8182, ioaddr + TX_INTR); } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } diff -ur --new-file old/linux/drivers/net/hamradio/Config.in new/linux/drivers/net/hamradio/Config.in --- old/linux/drivers/net/hamradio/Config.in Sun Jan 4 19:40:16 1998 +++ new/linux/drivers/net/hamradio/Config.in Tue Feb 3 00:18:15 1998 @@ -1,61 +1,27 @@ -# -# Amateur Radio protocols and AX.25 device configuration -# -# 19971130 Now in an own category to make correct compilation of the -# AX.25 stuff easier... -# Joerg Reuter DL1BKE +comment 'AX.25 network device drivers' -mainmenu_option next_comment -comment 'Amateur Radio support' -bool 'Amateur Radio support' CONFIG_HAMRADIO - -if [ "$CONFIG_HAMRADIO" != "n" ] ; then - if [ "$CONFIG_NET" != "n" ] ; then - comment 'Packet Radio protocols' - tristate 'Amateur Radio AX.25 Level 2 protocol' CONFIG_AX25 - if [ "$CONFIG_AX25" != "n" ]; then - bool ' AX.25 DAMA Slave support' CONFIG_AX25_DAMA_SLAVE -# bool ' AX.25 DAMA Master support' CONFIG_AX25_DAMA_MASTER - dep_tristate ' Amateur Radio NET/ROM protocol' CONFIG_NETROM $CONFIG_AX25 - dep_tristate ' Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25 - fi - - if [ "$CONFIG_AX25" != "n" ]; then - comment 'AX.25 network device drivers' - tristate 'Serial port KISS driver' CONFIG_MKISS -# tristate 'Serial port 6PACK driver' CONFIG_6PACK - tristate 'BPQ Ethernet driver' CONFIG_BPQETHER - - dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25 - tristate 'Z8530 SCC driver' CONFIG_SCC - if [ "$CONFIG_SCC" != "n" ]; then - bool ' additional delay for PA0HZP OptoSCC compatible boards' CONFIG_SCC_DELAY - bool ' support for TRX that feedback the tx signal to rx' CONFIG_SCC_TRXECHO - fi +dep_tristate 'Serial port KISS driver' CONFIG_MKISS $CONFIG_AX25 +# dep_tristate 'Serial port 6PACK driver' CONFIG_6PACK $CONFIG_AX25 +dep_tristate 'BPQ Ethernet driver' CONFIG_BPQETHER $CONFIG_AX25 - tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX - tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX - tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR - - tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM - if [ "$CONFIG_SOUNDMODEM" != "n" ]; then - bool ' soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC - bool ' soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS - bool ' soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200 - bool ' soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7 - bool ' soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8 - bool ' soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800 - bool ' soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 - fi - fi - fi - - comment 'Misc. hamradio protocols' - tristate 'Shortwave radio modem driver' CONFIG_HFMODEM - if [ "$CONFIG_HFMODEM" != "n" ]; then - bool ' HFmodem support for Soundblaster and compatible cards' CONFIG_HFMODEM_SBC - bool ' HFmodem support for WSS and Crystal cards' CONFIG_HFMODEM_WSS - fi +dep_tristate 'High-speed (DMA) SCC driver for AX.25' CONFIG_DMASCC $CONFIG_AX25 +dep_tristate 'Z8530 SCC driver' CONFIG_SCC $CONFIG_AX25 +if [ "$CONFIG_SCC" != "n" ]; then + bool ' additional delay for PA0HZP OptoSCC compatible boards' CONFIG_SCC_DELAY + bool ' support for TRX that feedback the tx signal to rx' CONFIG_SCC_TRXECHO fi + +dep_tristate 'BAYCOM ser12 fullduplex driver for AX.25' CONFIG_BAYCOM_SER_FDX $CONFIG_AX25 +dep_tristate 'BAYCOM ser12 halfduplex driver for AX.25' CONFIG_BAYCOM_SER_HDX $CONFIG_AX25 +dep_tristate 'BAYCOM picpar and par96 driver for AX.25' CONFIG_BAYCOM_PAR $CONFIG_AX25 -endmenu +dep_tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM $CONFIG_AX25 +if [ "$CONFIG_SOUNDMODEM" != "n" ]; then + bool ' soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC + bool ' soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS + bool ' soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200 + bool ' soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7 + bool ' soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8 + bool ' soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800 + bool ' soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 +fi diff -ur --new-file old/linux/drivers/net/hamradio/bpqether.c new/linux/drivers/net/hamradio/bpqether.c --- old/linux/drivers/net/hamradio/bpqether.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/hamradio/bpqether.c Tue Feb 10 22:07:49 1998 @@ -51,6 +51,7 @@ * call. * Fixed to match Linux networking * changes - 2.1.15. + * BPQ 004 Joerg(DL1BKE) Fixed to not lock up on ifconfig. */ #include @@ -78,6 +79,7 @@ #include #include #include +#include #include #include @@ -186,7 +188,11 @@ if (&bpq->axdev == dev) result = 1; - unregister_netdev(&bpq->axdev); + /* We should be locked, call + * unregister_netdevice directly + */ + + unregister_netdevice(&bpq->axdev); kfree(bpq); } @@ -217,7 +223,7 @@ dev = bpq_get_ax25_dev(dev); if (dev == NULL || dev->start == 0) { - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return 0; } @@ -230,7 +236,7 @@ if (!(bpq->acpt_addr[0] & 0x01) && memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN)) { printk(KERN_DEBUG "bpqether: wrong dest %s\n", bpq_print_ethaddr(eth->h_source)); - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return 0; } @@ -271,7 +277,7 @@ */ if (!dev->start) { bpq_check_devices(dev); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return -ENODEV; } @@ -285,14 +291,14 @@ if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { /* Ough! */ if ((newskb = skb_realloc_headroom(skb, AX25_BPQ_HEADER_LEN)) == NULL) { printk(KERN_WARNING "bpqether: out of memory\n"); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return -ENOMEM; } if (skb->sk != NULL) skb_set_owner_w(newskb, skb->sk); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); skb = newskb; } @@ -307,7 +313,7 @@ if ((dev = bpq_get_ether_dev(dev)) == NULL) { bpq->stats.tx_dropped++; - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return -ENODEV; } @@ -531,7 +537,9 @@ dev->name = buf; dev->init = bpq_dev_init; - if (register_netdev(dev) != 0) { + /* We should be locked, call register_netdevice() directly. */ + + if (register_netdevice(dev) != 0) { kfree(bpq); return -EIO; } diff -ur --new-file old/linux/drivers/net/hamradio/dmascc.c new/linux/drivers/net/hamradio/dmascc.c --- old/linux/drivers/net/hamradio/dmascc.c Sun Jan 4 19:40:16 1998 +++ new/linux/drivers/net/hamradio/dmascc.c Tue Feb 10 22:07:50 1998 @@ -41,7 +41,6 @@ #include #include #include -#include #include "z8530.h" @@ -801,7 +800,7 @@ /* Block a timer-based transmit from overlapping */ if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) { atomic_inc((void *) &priv->stats.tx_dropped); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } @@ -837,7 +836,7 @@ restore_flags(flags); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); priv->tx_sem = 0; return 0; diff -ur --new-file old/linux/drivers/net/hamradio/hdlcdrv.c new/linux/drivers/net/hamradio/hdlcdrv.c --- old/linux/drivers/net/hamradio/hdlcdrv.c Sun Nov 30 19:30:19 1997 +++ new/linux/drivers/net/hamradio/hdlcdrv.c Tue Feb 10 22:07:49 1998 @@ -446,18 +446,18 @@ } if (skb->data[0] != 0) { do_kiss_params(s, skb->data, skb->len); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); break; } pkt_len = skb->len-1; /* strip KISS byte */ if (pkt_len >= HDLCDRV_MAXFLEN || pkt_len < 2) { s->hdlctx.tx_state = 0; s->hdlctx.numflags = 1; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); break; } memcpy(s->hdlctx.buffer, skb->data+1, pkt_len); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); s->hdlctx.bp = s->hdlctx.buffer; append_crc_ccitt(s->hdlctx.buffer, pkt_len); s->hdlctx.len = pkt_len+2; /* the appended CRC */ @@ -681,7 +681,7 @@ i = s->ops->close(dev); /* Free any buffers left in the hardware transmit queue */ while ((skb = skb_dequeue(&s->send_queue))) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return i; } diff -ur --new-file old/linux/drivers/net/hamradio/mkiss.c new/linux/drivers/net/hamradio/mkiss.c --- old/linux/drivers/net/hamradio/mkiss.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/hamradio/mkiss.c Tue Feb 10 22:07:50 1998 @@ -420,7 +420,7 @@ if (tmp_ax != NULL) ax_lock(tmp_ax); ax_encaps(ax, skb->data, skb->len); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); } return 0; diff -ur --new-file old/linux/drivers/net/hamradio/pi2.c new/linux/drivers/net/hamradio/pi2.c --- old/linux/drivers/net/hamradio/pi2.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/hamradio/pi2.c Tue Feb 10 22:07:50 1998 @@ -408,7 +408,7 @@ } switch (lp->tstate) { case ACTIVE: - kfree_skb(lp->sndbuf, FREE_WRITE); + kfree_skb(lp->sndbuf); lp->sndbuf = NULL; lp->tstate = FLAGOUT; tdelay(lp, lp->squeldelay); @@ -726,7 +726,7 @@ /* stuffing a char satisfies Interrupt condition */ } else { /* No more to send */ - kfree_skb(lp->sndbuf, FREE_WRITE); + kfree_skb(lp->sndbuf); lp->sndbuf = NULL; if ((rdscc(lp->cardbase, cmd, R0) & 0x40)) { /* Did we underrun? */ @@ -778,7 +778,7 @@ switch (lp->tstate) { case ACTIVE: /* Unexpected underrun */ - kfree_skb(lp->sndbuf, FREE_WRITE); + kfree_skb(lp->sndbuf); lp->sndbuf = NULL; wrtscc(lp->cardbase, cmd, R0, SEND_ABORT); lp->tstate = FLAGOUT; @@ -1553,7 +1553,7 @@ /* Free any buffers left in the hardware transmit queue */ while ((ptr = skb_dequeue(&lp->sndq)) != NULL) - kfree_skb(ptr, FREE_WRITE); + kfree_skb(ptr); restore_flags(flags); diff -ur --new-file old/linux/drivers/net/hamradio/pt.c new/linux/drivers/net/hamradio/pt.c --- old/linux/drivers/net/hamradio/pt.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/net/hamradio/pt.c Tue Feb 10 22:07:50 1998 @@ -967,7 +967,7 @@ /* Free any buffers left in the hardware transmit queue */ while ((ptr = skb_dequeue(&lp->sndq)) != NULL) - kfree_skb(ptr, FREE_WRITE); + kfree_skb(ptr); restore_flags(flags); @@ -1185,7 +1185,7 @@ /* stuffing a char satisfies interrupt condition */ } else { /* No more to send */ - kfree_skb(lp->sndbuf, FREE_WRITE); + kfree_skb(lp->sndbuf); lp->sndbuf = NULL; if ((rdscc(lp->cardbase, cmd, R0) & TxEOM)) { @@ -1540,7 +1540,7 @@ #ifdef PT_DEBUG printk(KERN_DEBUG "PT: exisr(): unexpected underrun detected.\n"); #endif - kfree_skb(lp->sndbuf, FREE_WRITE); + kfree_skb(lp->sndbuf); lp->sndbuf = NULL; if (!lp->dmachan) { diff -ur --new-file old/linux/drivers/net/hamradio/scc.c new/linux/drivers/net/hamradio/scc.c --- old/linux/drivers/net/hamradio/scc.c Fri Dec 19 19:56:30 1997 +++ new/linux/drivers/net/hamradio/scc.c Tue Feb 10 22:07:50 1998 @@ -1,4 +1,4 @@ -#define RCS_ID "$Id: scc.c,v 1.71 1997/11/29 19:59:20 jreuter Exp jreuter $" +#define RCS_ID "$Id: scc.c,v 1.73 1998/01/29 17:38:51 jreuter Exp jreuter $" #define VERSION "3.0" #define BANNER "Z8530 SCC driver version "VERSION".dl1bke (experimental) by DL1BKE\n" @@ -6,6 +6,9 @@ /* * Please use z8530drv-utils-3.0 with this version. * ------------------ + * + * You can find a subset of the documentation in + * linux/Documentation/networking/z8530drv.txt. */ /* @@ -16,7 +19,7 @@ ******************************************************************** - Copyright (c) 1993, 1997 Joerg Reuter DL1BKE + Copyright (c) 1993, 1998 Joerg Reuter DL1BKE portions (c) 1993 Guido ten Dolle PE1NNZ @@ -89,7 +92,8 @@ 970108 - Fixed the remaining problems. 970402 - Hopefully fixed the problems with the new *_timer() routines, added calibration code. - 971012 - made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO + 971012 - Made SCC_DELAY a CONFIG option, added CONFIG_SCC_TRXECHO + 980129 - Small fix to avoid lock-up on initialization Thanks to all who contributed to this driver with ideas and bug reports! @@ -195,7 +199,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs *regs); static void scc_init_timer(struct scc_channel *scc); -static int scc_net_setup(struct scc_channel *scc, unsigned char *name); +static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev); static int scc_net_init(struct device *dev); static int scc_net_open(struct device *dev); static int scc_net_close(struct device *dev); @@ -320,12 +324,12 @@ if (scc->tx_buff != NULL) { - dev_kfree_skb(scc->tx_buff, FREE_WRITE); + dev_kfree_skb(scc->tx_buff); scc->tx_buff = NULL; } while (skb_queue_len(&scc->tx_queue)) - dev_kfree_skb(skb_dequeue(&scc->tx_queue), FREE_WRITE); + dev_kfree_skb(skb_dequeue(&scc->tx_queue)); restore_flags(flags); } @@ -368,7 +372,7 @@ if(scc->rx_buff != NULL) /* did we receive something? */ { scc->stat.rxerrs++; /* then count it as an error */ - kfree_skb(scc->rx_buff, FREE_READ); + kfree_skb(scc->rx_buff); scc->rx_buff = NULL; } } @@ -402,7 +406,7 @@ if (skb->len == 0) /* Paranoia... */ { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); scc->tx_buff = NULL; scc_tx_done(scc); Outb(scc->ctrl, RES_Tx_P); @@ -428,7 +432,7 @@ { Outb(scc->ctrl, RES_Tx_P); /* reset pending int */ cl(scc, R10, ABUNDER); /* send CRC */ - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); scc->tx_buff = NULL; scc->stat.tx_state = TXS_NEWFRAME; /* next frame... */ return; @@ -509,7 +513,7 @@ if (scc->tx_buff != NULL) { - dev_kfree_skb(scc->tx_buff, FREE_WRITE); + dev_kfree_skb(scc->tx_buff); scc->tx_buff = NULL; } @@ -559,7 +563,7 @@ #ifdef notdef printk(KERN_DEBUG "z8530drv: oops, scc_rxint() received huge frame...\n"); #endif - kfree_skb(skb, FREE_READ); + kfree_skb(skb); scc->rx_buff = NULL; Inb(scc->data); or(scc, R3, ENT_HM); @@ -589,7 +593,7 @@ or(scc,R3,ENT_HM); /* enter hunt mode for next flag */ if (skb != NULL) - kfree_skb(skb, FREE_READ); + kfree_skb(skb); scc->rx_buff = NULL; } @@ -605,7 +609,7 @@ scc->rx_buff = NULL; scc->stat.rxframes++; } else { /* a bad frame */ - kfree_skb(skb, FREE_READ); + kfree_skb(skb); scc->rx_buff = NULL; scc->stat.rxerrs++; } @@ -1529,7 +1533,7 @@ * Allocate device structure, err, instance, and register driver */ -static int scc_net_setup(struct scc_channel *scc, unsigned char *name) +static int scc_net_setup(struct scc_channel *scc, unsigned char *name, int addev) { unsigned char *buf; struct device *dev; @@ -1553,11 +1557,11 @@ dev->name = buf; dev->init = scc_net_init; - if (register_netdev(dev) != 0) + if ((addev? register_netdevice(dev) : register_netdev(dev)) != 0) { kfree(dev); - return -EIO; - } + return -EIO; + } return 0; } @@ -1667,7 +1671,7 @@ { if (skb->len == 0) { - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return; } @@ -1691,14 +1695,14 @@ if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } if (skb->len > scc->stat.bufsize || skb->len < 2) { scc->dev_stat.tx_dropped++; /* bogus frame */ - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } @@ -1711,7 +1715,7 @@ if (kisscmd) { scc_set_param(scc, kisscmd, *skb->data); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } @@ -1722,7 +1726,7 @@ { struct sk_buff *skb_del; skb_del = __skb_dequeue(&scc->tx_queue); - dev_kfree_skb(skb_del, FREE_WRITE); + dev_kfree_skb(skb_del); } __skb_queue_tail(&scc->tx_queue, skb); @@ -1868,7 +1872,7 @@ request_region(SCC_Info[2*Nchips+chan].ctrl, 1, "scc ctrl"); request_region(SCC_Info[2*Nchips+chan].data, 1, "scc data"); if (Nchips+chan != 0) - scc_net_setup(&SCC_Info[2*Nchips+chan], device_name); + scc_net_setup(&SCC_Info[2*Nchips+chan], device_name, 1); } } @@ -2178,7 +2182,7 @@ sprintf(devname,"%s0", SCC_DriverName); - result = scc_net_setup(SCC_Info, devname); + result = scc_net_setup(SCC_Info, devname, 0); if (result) { printk(KERN_ERR "z8530drv: cannot initialize module\n"); @@ -2203,7 +2207,7 @@ result = scc_init(); if (result == 0) - printk(KERN_INFO "Copyright 1993,1997 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n"); + printk(KERN_INFO "Copyright 1993,1998 Joerg Reuter DL1BKE (jreuter@poboxes.com)\n"); return result; } diff -ur --new-file old/linux/drivers/net/hamradio/soundmodem/gentbl.c new/linux/drivers/net/hamradio/soundmodem/gentbl.c --- old/linux/drivers/net/hamradio/soundmodem/gentbl.c Tue Aug 5 18:49:51 1997 +++ new/linux/drivers/net/hamradio/soundmodem/gentbl.c Sun Jan 25 19:05:46 1998 @@ -200,7 +200,9 @@ ? "\n\t" : ""); } } +#ifdef VERBOSE fprintf(stderr, "fsk9600: txfilt4: min = %f; max = %f\n", min, max); +#endif fprintf(f, "\n};\n\n"); min = max = 0; memset(c, 0, sizeof(c)); @@ -233,7 +235,9 @@ ? "\n\t" : ""); } } +#ifdef VERBOSE fprintf(stderr, "fsk9600: txfilt5: min = %f; max = %f\n", min, max); +#endif fprintf(f, "\n};\n\n"); } @@ -466,7 +470,9 @@ ? "\n\t" : ""); } } +#ifdef VERBOSE fprintf(stderr, "hapn4800: txfilt8: min = %f; max = %f\n", min, max); +#endif fprintf(f, "\n};\n\n"); min = max = 0; memset(c, 0, sizeof(c)); @@ -493,7 +499,9 @@ ? "\n\t" : ""); } } +#ifdef VERBOSE fprintf(stderr, "hapn4800: txfilt10: min = %f; max = %f\n", min, max); +#endif fprintf(f, "\n};\n\n"); /* * secondly generate tables for the PM transmitter modulator @@ -524,7 +532,9 @@ ? "\n\t" : ""); } } +#ifdef VERBOSE fprintf(stderr, "hapn4800: txfiltpm8: min = %f; max = %f\n", min, max); +#endif fprintf(f, "\n};\n\n"); min = max = 0; memset(c, 0, sizeof(c)); @@ -552,7 +562,9 @@ ? "\n\t" : ""); } } +#ifdef VERBOSE fprintf(stderr, "hapn4800: txfiltpm10: min = %f; max = %f\n", min, max); +#endif fprintf(f, "\n};\n\n"); } diff -ur --new-file old/linux/drivers/net/hp-plus.c new/linux/drivers/net/hp-plus.c --- old/linux/drivers/net/hp-plus.c Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/net/hp-plus.c Thu Feb 19 23:58:40 1998 @@ -466,10 +466,10 @@ if (dev->priv != NULL) { /* NB: hpp_close() handles free_irq */ int ioaddr = dev->base_addr - NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(ioaddr, HP_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/hp.c new/linux/drivers/net/hp.c --- old/linux/drivers/net/hp.c Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/net/hp.c Thu Feb 19 23:58:40 1998 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -432,11 +433,11 @@ struct device *dev = &dev_hp[this_dev]; if (dev->priv != NULL) { int ioaddr = dev->base_addr - NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; free_irq(dev->irq, dev); release_region(ioaddr, HP_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/hp100.c new/linux/drivers/net/hp100.c --- old/linux/drivers/net/hp100.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/hp100.c Wed Mar 18 06:21:43 1998 @@ -1,51 +1,77 @@ /* - ** hp100.c - ** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters - ** - ** $Id: hp100.c,v 1.14 1997/11/16 13:57:28 alan Exp $ - ** - ** Based on the HP100 driver written by Jaroslav Kysela - ** Extended for new busmaster capable chipsets by - ** Siegfried "Frieder" Loeffler (dg1sek) - ** - ** Maintained by: Jaroslav Kysela - ** - ** This driver has only been tested with - ** -- HP J2585B 10/100 Mbit/s PCI Busmaster - ** -- HP J2585A 10/100 Mbit/s PCI - ** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC - ** -- HP J2973 10 Mbit/s PCI 10base-T - ** -- HP J2573 10/100 ISA - ** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA - ** - ** but it should also work with the other CASCADE based adapters. - ** - ** TODO: - ** - J2573 seems to hang sometimes when in shared memory mode. - ** - Mode for Priority TX - ** - Check PCI registers, performance might be improved? - ** - To reduce interrupt load in busmaster, one could switch off - ** the interrupts that are used to refill the queues whenever the - ** queues are filled up to more than a certain threshold. - ** - ** - ** This source/code is public free; you can distribute it and/or modify - ** it under terms of the GNU General Public License (published by the - ** Free Software Foundation) either version two of this License, or any - ** later version. - ** - */ +** hp100.c +** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters +** +** $Id: hp100.c,v 1.56 1998/03/04 15:23:59 perex Exp perex $ +** +** Based on the HP100 driver written by Jaroslav Kysela +** Extended for new busmaster capable chipsets by +** Siegfried "Frieder" Loeffler (dg1sek) +** +** Maintained by: Jaroslav Kysela +** +** This driver has only been tested with +** -- HP J2585B 10/100 Mbit/s PCI Busmaster +** -- HP J2585A 10/100 Mbit/s PCI +** -- HP J2970 10 Mbit/s PCI Combo 10base-T/BNC +** -- HP J2973 10 Mbit/s PCI 10base-T +** -- HP J2573 10/100 ISA +** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA +** -- Compex FreedomLine 100/VG 10/100 Mbit/s ISA / EISA / PCI +** +** but it should also work with the other CASCADE based adapters. +** +** TODO: +** - J2573 seems to hang sometimes when in shared memory mode. +** - Mode for Priority TX +** - Check PCI registers, performance might be improved? +** - To reduce interrupt load in busmaster, one could switch off +** the interrupts that are used to refill the queues whenever the +** queues are filled up to more than a certain threshold. +** - some updates for EISA version of card +** +** +** This source/code is public free; you can distribute it and/or modify +** it under terms of the GNU General Public License (published by the +** Free Software Foundation) either version two of this License, or any +** later version. +** +** 1.55 -> 1.56 +** - removed printk in misc. interrupt and update statistics to allow +** monitoring of card status +** - timing changes in xmit routines, relogin to 100VG hub added when +** driver does reset +** - included fix for Compex FreedomLine PCI adapter +** +** 1.54 -> 1.55 +** - fixed bad initialization in init_module +** - added Compex FreedomLine adapter +** - some fixes in card initialization +** +** 1.53 -> 1.54 +** - added hardware multicast filter support (doesn't work) +** - little changes in hp100_sense_lan routine +** - added support for Coax and AUI (J2970) +** - fix for multiple cards and hp100_mode parameter (insmod) +** - fix for shared IRQ +** +** 1.52 -> 1.53 +** - fixed bug in multicast support +** +*/ -#define HP100_DEFAULT_PRIORITY_TX 0 +#define HP100_DEFAULT_PRIORITY_TX 0 #undef HP100_DEBUG -#undef HP100_DEBUG_B /* Trace */ -#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */ +#undef HP100_DEBUG_B /* Trace */ +#undef HP100_DEBUG_BM /* Debug busmaster code (PDL stuff) */ + +#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */ +#undef HP100_DEBUG_TX +#undef HP100_DEBUG_IRQ +#undef HP100_DEBUG_RX -#undef HP100_DEBUG_TRAINING /* Debug login-to-hub procedure */ -#undef HP100_DEBUG_TX -#undef HP100_DEBUG_IRQ -#undef HP100_DEBUG_RX +#undef HP100_MULTICAST_FILTER /* Need to be debugged... */ #include #include @@ -58,7 +84,6 @@ #include #include #include -#include #include #include @@ -67,7 +92,7 @@ #include #include -#include /* for CONFIG_PCI */ +#include /* for CONFIG_PCI */ #include #if LINUX_VERSION_CODE < 0x020100 @@ -79,6 +104,12 @@ typedef struct net_device_stats hp100_stats_t; #endif +#ifndef __initfunc +#define __initfunc(__initarg) __initarg +#else +#include +#endif + #include "hp100.h" /* @@ -98,8 +129,14 @@ #ifndef PCI_DEVICE_ID_COMPEX_ENET100VG4 #define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 #endif +#ifndef PCI_VENDOR_ID_COMPEX2 +#define PCI_VENDOR_ID_COMPEX2 0x101a +#endif +#ifndef PCI_DEVICE_ID_COMPEX2_100VG +#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 +#endif -#define HP100_REGION_SIZE 0x20 /* for ioports */ +#define HP100_REGION_SIZE 0x20 /* for ioports */ #define HP100_MAX_PACKET_SIZE (1536+4) #define HP100_MIN_PACKET_SIZE 60 @@ -119,135 +156,167 @@ */ struct hp100_eisa_id { - u_int id; - const char *name; - u_char bus; + u_int id; + const char *name; + u_char bus; +}; + +struct hp100_pci_id { + u_short vendor; + u_short device; }; struct hp100_private { - struct hp100_eisa_id *id; - u_short chip; - u_short soft_model; - u_int memory_size; - u_short rx_ratio; /* 1 - 99 */ - u_short priority_tx; /* != 0 - priority tx */ - u_short mode; /* PIO, Shared Mem or Busmaster */ - u_char bus; - u_char pci_bus; - u_char pci_device_fn; - short mem_mapped; /* memory mapped access */ - u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ - u_int *mem_ptr_phys; /* physical memory mapped area */ - short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ - int hub_status; /* was login to hub successful? */ - u_char mac1_mode; - u_char mac2_mode; - hp100_stats_t stats; - - /* Rings for busmaster mode: */ - hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ - hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ - hp100_ring_t *txrhead; /* Head (oldest) index into txring */ - hp100_ring_t *txrtail; /* Tail (newest) index into txring */ - - hp100_ring_t rxring[MAX_RX_PDL]; - hp100_ring_t txring[MAX_TX_PDL]; - - u_int *page_vaddr; /* Virtual address of allocated page */ - u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ - int rxrcommit; /* # Rx PDLs commited to adapter */ - int txrcommit; /* # Tx PDLs commited to adapter */ + struct hp100_eisa_id *id; + u_short chip; + u_short soft_model; + u_int memory_size; + u_int virt_memory_size; + u_short rx_ratio; /* 1 - 99 */ + u_short priority_tx; /* != 0 - priority tx */ + u_short mode; /* PIO, Shared Mem or Busmaster */ + u_char bus; + u_char pci_bus; + u_char pci_device_fn; + short mem_mapped; /* memory mapped access */ + u_int *mem_ptr_virt; /* virtual memory mapped area, maybe NULL */ + u_int *mem_ptr_phys; /* physical memory mapped area */ + short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */ + int hub_status; /* was login to hub successful? */ + u_char mac1_mode; + u_char mac2_mode; + u_char hash_bytes[ 8 ]; + hp100_stats_t stats; + + /* Rings for busmaster mode: */ + hp100_ring_t *rxrhead; /* Head (oldest) index into rxring */ + hp100_ring_t *rxrtail; /* Tail (newest) index into rxring */ + hp100_ring_t *txrhead; /* Head (oldest) index into txring */ + hp100_ring_t *txrtail; /* Tail (newest) index into txring */ + + hp100_ring_t rxring[ MAX_RX_PDL ]; + hp100_ring_t txring[ MAX_TX_PDL ]; + + u_int *page_vaddr; /* Virtual address of allocated page */ + u_int *page_vaddr_algn; /* Aligned virtual address of allocated page */ + int rxrcommit; /* # Rx PDLs commited to adapter */ + int txrcommit; /* # Tx PDLs commited to adapter */ }; /* * variables */ -static struct hp100_eisa_id hp100_eisa_ids[] = -{ +static struct hp100_eisa_id hp100_eisa_ids[] = { /* 10/100 EISA card with revision A Cascade chip */ - {0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA}, + { 0x80F1F022, "HP J2577 rev A", HP100_BUS_EISA }, /* 10/100 ISA card with revision A Cascade chip */ - {0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA}, + { 0x50F1F022, "HP J2573 rev A", HP100_BUS_ISA }, /* 10 only EISA card with Cascade chip */ - {0x2019F022, "HP 27248B", HP100_BUS_EISA}, + { 0x2019F022, "HP 27248B", HP100_BUS_EISA }, /* 10/100 EISA card with Cascade chip */ - {0x4019F022, "HP J2577", HP100_BUS_EISA}, + { 0x4019F022, "HP J2577", HP100_BUS_EISA }, /* 10/100 ISA card with Cascade chip */ - {0x5019F022, "HP J2573", HP100_BUS_ISA}, + { 0x5019F022, "HP J2573", HP100_BUS_ISA }, /* 10/100 PCI card - old J2585A */ - {0x1030103c, "HP J2585A", HP100_BUS_PCI}, + { 0x1030103c, "HP J2585A", HP100_BUS_PCI }, /* 10/100 PCI card - new J2585B - master capable */ - {0x1041103c, "HP J2585B", HP100_BUS_PCI}, + { 0x1041103c, "HP J2585B", HP100_BUS_PCI }, /* 10 Mbit Combo Adapter */ - {0x1042103c, "HP J2970", HP100_BUS_PCI}, + { 0x1042103c, "HP J2970", HP100_BUS_PCI }, /* 10 Mbit 10baseT Adapter */ - {0x1040103c, "HP J2973", HP100_BUS_PCI}, + { 0x1040103c, "HP J2973", HP100_BUS_PCI }, /* 10/100 EISA card from Compex */ - {0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA}, + { 0x0103180e, "ReadyLink ENET100-VG4", HP100_BUS_EISA }, + /* 10/100 EISA card from Compex - FreedomLine (sq5bpf) */ + /* Note: plhbrod@mbox.vol.cz reported that same ID have ISA */ + /* version of adapter, too... */ + { 0x0104180e, "FreedomLine 100/VG", HP100_BUS_EISA }, + + /* 10/100 PCI card from Compex - FreedomLine + * + * I think this card doesn't like aic7178 scsi controller, but + * I haven't tested this much. It works fine on diskless machines. + * Jacek Lipkowski + */ + { 0x021211f6, "FreedomLine 100/VG", HP100_BUS_PCI }, + /* 10/100 PCI card from Compex (J2585A compatible) */ - {0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI} + { 0x011211f6, "ReadyLink ENET100-VG4", HP100_BUS_PCI } + +}; + +#define HP100_EISA_IDS_SIZE (sizeof(hp100_eisa_ids)/sizeof(struct hp100_eisa_id)) + +static struct hp100_pci_id hp100_pci_ids[] = { + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A }, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B }, + { PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4 }, + { PCI_VENDOR_ID_COMPEX2, PCI_DEVICE_ID_COMPEX2_100VG } }; +#define HP100_PCI_IDS_SIZE (sizeof(hp100_pci_ids)/sizeof(struct hp100_pci_id)) + static int hp100_rx_ratio = HP100_DEFAULT_RX_RATIO; static int hp100_priority_tx = HP100_DEFAULT_PRIORITY_TX; static int hp100_mode = 1; #ifdef LINUX_2_1 -MODULE_PARM(hp100_rx_ratio, "1i"); -MODULE_PARM(hp100_priority_tx, "1i"); -MODULE_PARM(hp100_mode, "1i"); +MODULE_PARM( hp100_rx_ratio, "1i" ); +MODULE_PARM( hp100_priority_tx, "1i" ); +MODULE_PARM( hp100_mode, "1i" ); #endif /* * prototypes */ -static int hp100_probe1(struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn); -static int hp100_open(struct device *dev); -static int hp100_close(struct device *dev); -static int hp100_start_xmit(struct sk_buff *skb, struct device *dev); -static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev); -static void hp100_rx(struct device *dev); -static hp100_stats_t *hp100_get_stats(struct device *dev); -static void hp100_update_stats(struct device *dev); -static void hp100_clear_stats(int ioaddr); -static void hp100_set_multicast_list(struct device *dev); -static void hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void hp100_start_interface(struct device *dev); -static void hp100_stop_interface(struct device *dev); -static void hp100_load_eeprom(struct device *dev); -static int hp100_sense_lan(struct device *dev); -static int hp100_login_to_vg_hub(struct device *dev, u_short force_relogin); -static int hp100_down_vg_link(struct device *dev); -static void hp100_cascade_reset(struct device *dev, u_short enable); -static void hp100_BM_shutdown(struct device *dev); -static void hp100_mmuinit(struct device *dev); -static void hp100_init_pdls(struct device *dev); -static int hp100_init_rxpdl(register hp100_ring_t * ringptr, register u_int * pdlptr); -static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u_int * pdlptr); -static void hp100_rxfill(struct device *dev); -static void hp100_hwinit(struct device *dev); -static void hp100_clean_txring(struct device *dev); +static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn ); +static int hp100_open( struct device *dev ); +static int hp100_close( struct device *dev ); +static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ); +static int hp100_start_xmit_bm (struct sk_buff *skb, struct device *dev ); +static void hp100_rx( struct device *dev ); +static hp100_stats_t *hp100_get_stats( struct device *dev ); +static void hp100_misc_interrupt( struct device *dev ); +static void hp100_update_stats( struct device *dev ); +static void hp100_clear_stats( int ioaddr ); +static void hp100_set_multicast_list( struct device *dev); +static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs ); +static void hp100_start_interface( struct device *dev ); +static void hp100_stop_interface( struct device *dev ); +static void hp100_load_eeprom( struct device *dev, u_short ioaddr ); +static int hp100_sense_lan( struct device *dev ); +static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin ); +static int hp100_down_vg_link( struct device *dev ); +static void hp100_cascade_reset( struct device *dev, u_short enable ); +static void hp100_BM_shutdown( struct device *dev ); +static void hp100_mmuinit( struct device *dev ); +static void hp100_init_pdls( struct device *dev ); +static int hp100_init_rxpdl( struct device *dev, register hp100_ring_t *ringptr, register u_int *pdlptr); +static int hp100_init_txpdl( struct device *dev, register hp100_ring_t *ringptr, register u_int *pdlptr); +static void hp100_rxfill( struct device *dev ); +static void hp100_hwinit( struct device *dev ); +static void hp100_clean_txring( struct device *dev ); #ifdef HP100_DEBUG -static void hp100_RegisterDump(struct device *dev); +static void hp100_RegisterDump( struct device *dev ); #endif /* TODO: This function should not really be needed in a good design... */ -static void wait(void) +static void wait( void ) { - udelay(1000); + udelay( 1000 ); } /* @@ -255,863 +324,984 @@ * These functions should - if possible - avoid doing write operations * since this could cause problems when the card is not installed. */ - -__initfunc(int hp100_probe(struct device *dev)) + +__initfunc(int hp100_probe( struct device *dev )) { - int base_addr = dev ? dev->base_addr : 0; - int ioaddr = 0; + int base_addr = dev ? dev -> base_addr : 0; + int ioaddr = 0; #ifdef CONFIG_PCI - int pci_start_index = 0; + int pci_start_index = 0; #endif #ifdef HP100_DEBUG_B - hp100_outw(0x4200, TRACE); - printk("hp100: probe\n"); + hp100_outw( 0x4200, TRACE ); + printk( "hp100: %s: probe\n", dev->name ); #endif - if (base_addr > 0xff) { /* Check a single specified location. */ - if (check_region(base_addr, HP100_REGION_SIZE)) - return -EINVAL; - if (base_addr < 0x400) - return hp100_probe1(dev, base_addr, HP100_BUS_ISA, 0, 0); - else - return hp100_probe1(dev, base_addr, HP100_BUS_EISA, 0, 0); - } else + if ( base_addr > 0xff ) /* Check a single specified location. */ + { + if ( check_region( base_addr, HP100_REGION_SIZE ) ) return -EINVAL; + if ( base_addr < 0x400 ) + return hp100_probe1( dev, base_addr, HP100_BUS_ISA, 0, 0 ); + if ( EISA_bus && base_addr >= 0x1c38 && ( (base_addr - 0x1c38) & 0x3ff ) == 0 ) + return hp100_probe1( dev, base_addr, HP100_BUS_EISA, 0, 0 ); +#ifdef CONFIG_PCI + printk( "hp100: %s: You may specify card # in i/o address parameter for PCI bus...", dev->name ); + return hp100_probe1( dev, base_addr, HP100_BUS_PCI, 0, 0 ); +#else + return -ENODEV; +#endif + } + else #ifdef CONFIG_PCI - if (base_addr > 0 && base_addr < 8 + 1) - pci_start_index = 0x100 | (base_addr - 1); - else + if ( base_addr > 0 && base_addr < 8 + 1 ) + pci_start_index = 0x100 | ( base_addr - 1 ); + else #endif - if (base_addr != 0) - return -ENXIO; + if ( base_addr != 0 ) return -ENXIO; - /* at first - scan PCI bus(es) */ + /* at first - scan PCI bus(es) */ #ifdef CONFIG_PCI - if (pcibios_present()) { - int pci_index; + if ( pcibios_present() ) + { + int pci_index; #ifdef HP100_DEBUG_PCI - printk("hp100: PCI BIOS is present, checking for devices..\n"); + printk( "hp100: %s: PCI BIOS is present, checking for devices..\n", dev->name ); #endif - for (pci_index = pci_start_index & 7; pci_index < 8; pci_index++) { - u_char pci_bus, pci_device_fn; - u_short pci_command; - - if ((pcibios_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585A, - pci_index, &pci_bus, - &pci_device_fn) != 0) && - (pcibios_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_J2585B, - pci_index, &pci_bus, - &pci_device_fn) != 0) && - (pcibios_find_device(PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_ENET100VG4, - pci_index, &pci_bus, - &pci_device_fn) != 0)) - break; - - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &ioaddr); - - ioaddr &= ~3; /* remove I/O space marker in bit 0. */ - - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - if (!(pci_command & PCI_COMMAND_MASTER)) { -#ifdef HP100_DEBUG - printk("hp100: PCI Master Bit has not been set. Setting...\n"); -#endif - pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, pci_command); - } + for ( pci_index = pci_start_index & 7; pci_index < 8; pci_index++ ) + { + u_char pci_bus, pci_device_fn; + u_short pci_command; + int pci_id_index; + + for ( pci_id_index = 0; pci_id_index < HP100_PCI_IDS_SIZE; pci_id_index++ ) + if ( pcibios_find_device( hp100_pci_ids[ pci_id_index ].vendor, + hp100_pci_ids[ pci_id_index ].device, + pci_index, &pci_bus, + &pci_device_fn ) == 0 ) goto __pci_found; + break; + + __pci_found: + pcibios_read_config_dword( pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &ioaddr ); + + ioaddr &= ~3; /* remove I/O space marker in bit 0. */ + + if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; + + pcibios_read_config_word( pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command ); + if ( !( pci_command & PCI_COMMAND_IO ) ) + { +#ifdef HP100_DEBUG + printk( "hp100: %s: PCI I/O Bit has not been set. Setting...\n", dev->name ); +#endif + pci_command |= PCI_COMMAND_IO; + pcibios_write_config_word( pci_bus, pci_device_fn, + PCI_COMMAND, pci_command ); + } + if ( !( pci_command & PCI_COMMAND_MASTER ) ) + { +#ifdef HP100_DEBUG + printk( "hp100: %s: PCI Master Bit has not been set. Setting...\n", dev->name ); +#endif + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word( pci_bus, pci_device_fn, + PCI_COMMAND, pci_command ); + } +#ifdef HP100_DEBUG + printk( "hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr ); +#endif + if ( hp100_probe1( dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn ) == 0 ) + return 0; + } + } + if ( pci_start_index > 0 ) return -ENODEV; +#endif /* CONFIG_PCI */ + + /* Second: Probe all EISA possible port regions (if EISA bus present) */ + for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 ) + { + if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; + if ( hp100_probe1( dev, ioaddr, HP100_BUS_EISA, 0, 0 ) == 0 ) return 0; + } + + /* Third Probe all ISA possible port regions */ + for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 ) + { + if ( check_region( ioaddr, HP100_REGION_SIZE ) ) continue; + if ( hp100_probe1( dev, ioaddr, HP100_BUS_ISA, 0, 0 ) == 0 ) return 0; + } + + return -ENODEV; +} + + +__initfunc(static int hp100_probe1( struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn )) +{ + int i; + + u_char uc, uc_1; + u_int eisa_id; + u_int chip; + u_int memory_size = 0, virt_memory_size = 0; + u_short local_mode, lsw; + short mem_mapped; + u_int *mem_ptr_phys, *mem_ptr_virt; + struct hp100_private *lp; + struct hp100_eisa_id *eid; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4201, TRACE ); + printk("hp100: %s: probe1\n",dev->name); +#endif + + if ( dev == NULL ) + { +#ifdef HP100_DEBUG + printk( "hp100_probe1: %s: dev == NULL ?\n", dev->name ); +#endif + return EIO; + } + + if ( hp100_inw( HW_ID ) != HP100_HW_ID_CASCADE ) + { + return -ENODEV; + } + else + { + chip = hp100_inw( PAGING ) & HP100_CHIPID_MASK; +#ifdef HP100_DEBUG + if ( chip == HP100_CHIPID_SHASTA ) + printk("hp100: %s: Shasta Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if ( chip == HP100_CHIPID_RAINIER ) + printk("hp100: %s: Rainier Chip detected. (This is a pre 802.12 chip)\n", dev->name); + else if ( chip == HP100_CHIPID_LASSEN ) + printk("hp100: %s: Lassen Chip detected.\n", dev->name); + else + printk("hp100: %s: Warning: Unknown CASCADE chip (id=0x%.4x).\n",dev->name,chip); +#endif + } + + dev->base_addr = ioaddr; + + hp100_page( ID_MAC_ADDR ); + for ( i = uc = eisa_id = 0; i < 4; i++ ) + { + eisa_id >>= 8; + uc_1 = hp100_inb( BOARD_ID + i ); + eisa_id |= uc_1 << 24; + uc += uc_1; + } + uc += hp100_inb( BOARD_ID + 4 ); + + if ( uc != 0xff ) /* bad checksum? */ + { + printk("hp100_probe: %s: bad EISA ID checksum at base port 0x%x\n", dev->name, ioaddr ); + return -ENODEV; + } + + for ( i=0; i < HP100_EISA_IDS_SIZE; i++) + if ( hp100_eisa_ids[ i ].id == eisa_id ) + break; + if ( i >= HP100_EISA_IDS_SIZE ) { + for ( i = 0; i < HP100_EISA_IDS_SIZE; i++) + if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) ) + break; + if ( i >= HP100_EISA_IDS_SIZE ) { + printk( "hp100_probe: %s: card at port 0x%x isn't known (id = 0x%x)\n", dev -> name, ioaddr, eisa_id ); + return -ENODEV; + } + } + eid = &hp100_eisa_ids[ i ]; + if ( ( eid->id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) ) + { + printk( "hp100_probe: %s: newer version of card %s at port 0x%x - unsupported\n", + dev->name, eid->name, ioaddr ); + return -ENODEV; + } + + for ( i = uc = 0; i < 7; i++ ) + uc += hp100_inb( LAN_ADDR + i ); + if ( uc != 0xff ) + { + printk("hp100_probe: %s: bad lan address checksum (card %s at port 0x%x)\n", + dev->name, eid->name, ioaddr ); + return -EIO; + } + + /* Make sure, that all registers are correctly updated... */ + + hp100_load_eeprom( dev, ioaddr ); + wait(); + + /* + * Determine driver operation mode + * + * Use the variable "hp100_mode" upon insmod or as kernel parameter to + * force driver modes: + * hp100_mode=1 -> default, use busmaster mode if configured. + * hp100_mode=2 -> enable shared memory mode + * hp100_mode=3 -> force use of i/o mapped mode. + * hp100_mode=4 -> same as 1, but re-set the enable bit on the card. + */ + + /* + * LSW values: + * 0x2278 -> J2585B, PnP shared memory mode + * 0x2270 -> J2585B, shared memory mode, 0xdc000 + * 0xa23c -> J2585B, I/O mapped mode + * 0x2240 -> EISA COMPEX, BusMaster (Shasta Chip) + * 0x2220 -> EISA HP, I/O (Shasta Chip) + * 0x2260 -> EISA HP, BusMaster (Shasta Chip) + */ + +#if 0 + local_mode = 0x2270; + hp100_outw(0xfefe,OPTION_LSW); + hp100_outw(local_mode|HP100_SET_LB|HP100_SET_HB,OPTION_LSW); +#endif + + /* hp100_mode value maybe used in future by another card */ + local_mode=hp100_mode; + if ( local_mode < 1 || local_mode > 4 ) + local_mode = 1; /* default */ +#ifdef HP100_DEBUG + printk( "hp100: %s: original LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) ); +#endif + + if(local_mode==3) + { + hp100_outw(HP100_MEM_EN|HP100_RESET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN|HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW); + printk("hp100: %s: IO mapped mode forced.\n", dev->name); + } + else if(local_mode==2) + { + hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_IO_EN |HP100_SET_LB, OPTION_LSW); + hp100_outw(HP100_BM_WRITE|HP100_BM_READ|HP100_RESET_HB, OPTION_LSW); + printk("hp100: %s: Shared memory mode requested.\n", dev->name); + } + else if(local_mode==4) + { + if(chip==HP100_CHIPID_LASSEN) + { + hp100_outw(HP100_BM_WRITE| + HP100_BM_READ | HP100_SET_HB, OPTION_LSW); + hp100_outw(HP100_IO_EN | + HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); + printk("hp100: %s: Busmaster mode requested.\n",dev->name); + } + local_mode=1; + } + + if(local_mode==1) /* default behaviour */ + { + lsw = hp100_inw(OPTION_LSW); + + if ( (lsw & HP100_IO_EN) && + (~lsw & HP100_MEM_EN) && + (~lsw & (HP100_BM_WRITE|HP100_BM_READ)) ) + { +#ifdef HP100_DEBUG + printk("hp100: %s: IO_EN bit is set on card.\n",dev->name); +#endif + local_mode=3; + } + else if ( chip == HP100_CHIPID_LASSEN && + ( lsw & (HP100_BM_WRITE|HP100_BM_READ) ) == + (HP100_BM_WRITE|HP100_BM_READ) ) + { + printk("hp100: %s: Busmaster mode enabled.\n",dev->name); + hp100_outw(HP100_MEM_EN|HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); + } + else + { +#ifdef HP100_DEBUG + printk("hp100: %s: Card not configured for BM or BM not supported with this card.\n", dev->name ); + printk("hp100: %s: Trying shared memory mode.\n", dev->name); +#endif + /* In this case, try shared memory mode */ + local_mode=2; + hp100_outw(HP100_MEM_EN|HP100_SET_LB, OPTION_LSW); + /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */ + } + } + +#ifdef HP100_DEBUG + printk( "hp100: %s: new LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) ); +#endif + + /* Check for shared memory on the card, eventually remap it */ + hp100_page( HW_MAP ); + mem_mapped = (( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN ) ) != 0); + mem_ptr_phys = mem_ptr_virt = NULL; + memory_size = (8192<<( (hp100_inb(SRAM)>>5)&0x07)); + virt_memory_size = 0; + + /* For memory mapped or busmaster mode, we want the memory address */ + if ( mem_mapped || (local_mode==1)) + { + mem_ptr_phys = (u_int *)( hp100_inw( MEM_MAP_LSW ) | + ( hp100_inw( MEM_MAP_MSW ) << 16 ) ); + (u_int)mem_ptr_phys &= ~0x1fff; /* 8k alignment */ + + if ( bus == HP100_BUS_ISA && ( (u_long)mem_ptr_phys & ~0xfffff ) != 0 ) + { + printk("hp100: %s: Can only use programmed i/o mode.\n", dev->name); + mem_ptr_phys = NULL; + mem_mapped = 0; + local_mode=3; /* Use programmed i/o */ + } + + /* We do not need access to shared memory in busmaster mode */ + /* However in slave mode we need to remap high (>1GB) card memory */ + if(local_mode!=1) /* = not busmaster */ + { + if ( bus == HP100_BUS_PCI && mem_ptr_phys >= (u_int *)0x100000 ) + { + /* We try with smaller memory sizes, if ioremap fails */ + for(virt_memory_size = memory_size; virt_memory_size>16383; virt_memory_size>>=1) + { + if((mem_ptr_virt=ioremap((u_long)mem_ptr_phys,virt_memory_size))==NULL) + { #ifdef HP100_DEBUG - printk("hp100: PCI adapter found at 0x%x\n", ioaddr); + printk( "hp100: %s: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys ); #endif - if (hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pci_bus, pci_device_fn) == 0) - return 0; - } - } - if (pci_start_index > 0) - return -ENODEV; -#endif /* CONFIG_PCI */ - - /* Second: Probe all EISA possible port regions (if EISA bus present) */ - for (ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_EISA, 0, 0) == 0) - return 0; - } - - /* Third Probe all ISA possible port regions */ - for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { - if (check_region(ioaddr, HP100_REGION_SIZE)) - continue; - if (hp100_probe1(dev, ioaddr, HP100_BUS_ISA, 0, 0) == 0) - return 0; - } - - return -ENODEV; -} - - -__initfunc(static int hp100_probe1(struct device *dev, int ioaddr, u_char bus, u_char pci_bus, u_char pci_device_fn)) -{ - int i; - - u_char uc, uc_1; - u_int eisa_id; - u_int chip; - u_int memory_size = 0; - short mem_mapped; - u_int *mem_ptr_phys, *mem_ptr_virt; - struct hp100_private *lp; - struct hp100_eisa_id *eid; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4201, TRACE); - printk("hp100: probe1\n"); -#endif - - if (dev == NULL) { -#ifdef HP100_DEBUG - printk("hp100_probe1: dev == NULL ?\n"); -#endif - return EIO; - } - if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE) { - return -ENODEV; - } else { - chip = hp100_inw(PAGING) & HP100_CHIPID_MASK; -#ifdef HP100_DEBUG - if (chip == HP100_CHIPID_SHASTA) - printk("hp100: Shasta Chip detected. (This is a pre 802.12 chip)\n"); - else if (chip == HP100_CHIPID_RAINIER) - printk("hp100: Rainier Chip detected. (This is a pre 802.12 chip)\n"); - else if (chip == HP100_CHIPID_LASSEN) - printk("hp100: Lassen Chip detected.\n"); - else - printk("hp100: Warning: Unknown CASCADE chip (id=0x%.4x).\n", chip); -#endif - } - - dev->base_addr = ioaddr; - - hp100_page(ID_MAC_ADDR); - for (i = uc = eisa_id = 0; i < 4; i++) { - eisa_id >>= 8; - uc_1 = hp100_inb(BOARD_ID + i); - eisa_id |= uc_1 << 24; - uc += uc_1; - } - uc += hp100_inb(BOARD_ID + 4); - - if (uc != 0xff) { /* bad checksum? */ - printk("hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr); - return -ENODEV; - } - for (i = 0; i < sizeof(hp100_eisa_ids) / sizeof(struct hp100_eisa_id); i++) - if ((hp100_eisa_ids[i].id & 0xf0ffffff) == (eisa_id & 0xf0ffffff)) - break; - if (i >= sizeof(hp100_eisa_ids) / sizeof(struct hp100_eisa_id)) { - printk("hp100_probe1: card at port 0x%x isn't known (id = 0x%x)\n", ioaddr, eisa_id); - return -ENODEV; - } - eid = &hp100_eisa_ids[i]; - if ((eid->id & 0x0f000000) < (eisa_id & 0x0f000000)) { - printk("hp100_probe1: newer version of card %s at port 0x%x - unsupported\n", - eid->name, ioaddr); - return -ENODEV; - } - for (i = uc = 0; i < 7; i++) - uc += hp100_inb(LAN_ADDR + i); - if (uc != 0xff) { - printk("hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n", - eid->name, ioaddr); - return -EIO; - } - /* Determine driver operation mode - - * Use the variable "hp100_mode" upon insmod or as kernel parameter to - * force driver modes: - * hp100_mode=1 -> default, use busmaster mode if configured. - * hp100_mode=2 -> enable shared memory mode - * hp100_mode=3 -> force use of i/o mapped mode. - * hp100_mode=4 -> same as 1, but re-set the enable bit on the card. - */ - - if (hp100_mode == 3) { - hp100_outw(HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: IO mapped mode forced.\n"); - } else if (hp100_mode == 2) { - hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_BM_WRITE | HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - printk("hp100: Shared memory mode requested.\n"); - } else if (hp100_mode == 4) { - if (chip == HP100_CHIPID_LASSEN) { - hp100_outw(HP100_BM_WRITE | - HP100_BM_READ | HP100_SET_HB, OPTION_LSW); - hp100_outw(HP100_IO_EN | - HP100_MEM_EN | HP100_RESET_LB, OPTION_LSW); - printk("hp100: Busmaster mode requested.\n"); - } - hp100_mode = 1; - } - if (hp100_mode == 1) { /* default behaviour */ - if ((hp100_inw(OPTION_LSW) & HP100_IO_EN) && - (~hp100_inw(OPTION_LSW) & HP100_MEM_EN) && - (~hp100_inw(OPTION_LSW) & (HP100_BM_WRITE | HP100_BM_READ)) - ) { -#ifdef HP100_DEBUG - printk("hp100: IO_EN bit is set on card.\n"); -#endif - hp100_mode = 3; - } else if ((chip == HP100_CHIPID_LASSEN) && - ((hp100_inw(OPTION_LSW) & (HP100_BM_WRITE | HP100_BM_READ)) == - (HP100_BM_WRITE | HP100_BM_READ))) { - printk("hp100: Busmaster mode enabled.\n"); - hp100_outw(HP100_MEM_EN | HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); - } else { -#ifdef HP100_DEBUG - printk("hp100: Card not configured for BM or BM not supported with this card. Trying shared memory mode.\n"); -#endif - /* In this case, try shared memory mode */ - hp100_mode = 2; - hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); - /* hp100_outw(HP100_IO_EN|HP100_RESET_LB, OPTION_LSW); */ - } - } - /* Check for shared memory on the card, eventually remap it */ - hp100_page(HW_MAP); - mem_mapped = ((hp100_inw(OPTION_LSW) & (HP100_MEM_EN)) != 0); - mem_ptr_phys = mem_ptr_virt = NULL; - memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07)); - - /* For memory mapped or busmaster mode, we want the memory address */ - if (mem_mapped || (hp100_mode == 1)) { - mem_ptr_phys = (u_int *) (hp100_inw(MEM_MAP_LSW) | - (hp100_inw(MEM_MAP_MSW) << 16)); - (u_int) mem_ptr_phys &= ~0x1fff; /* 8k alignment */ - - if (bus == HP100_BUS_ISA && ((u_long) mem_ptr_phys & ~0xfffff) != 0) { - printk("hp100: Can only use programmed i/o mode.\n"); - mem_ptr_phys = NULL; - mem_mapped = 0; - hp100_mode = 3; /* Use programmed i/o */ - } - /* We do not need access to shared memory in busmaster mode */ - /* However in slave mode we need to remap high (>1GB) card memory */ - if (hp100_mode != 1) { /* = not busmaster */ - if (bus == HP100_BUS_PCI) { - /* We try with smaller memory sizes, if ioremap fails */ - for (; memory_size > 16383; memory_size = memory_size / 2) { - if ((mem_ptr_virt = ioremap((u_long) mem_ptr_phys, memory_size)) == NULL) { -#ifdef HP100_DEBUG - printk("hp100: ioremap for 0x%x bytes high PCI memory at 0x%lx failed\n", memory_size, (u_long) mem_ptr_phys); -#endif - } else { -#ifdef HP100_DEBUG - printk("hp100: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", memory_size, (u_long) mem_ptr_phys, (u_long) mem_ptr_virt); -#endif - break; - } - } - - if (mem_ptr_virt == NULL) { /* all ioremap tries failed */ - printk("hp100: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n"); - hp100_mode = 3; - memory_size = (8192 << ((hp100_inb(SRAM) >> 5) & 0x07)); - } - } + } + else + { +#ifdef HP100_DEBUG + printk( "hp100: %s: remapped 0x%x bytes high PCI memory at 0x%lx to 0x%lx.\n", dev->name, virt_memory_size, (u_long)mem_ptr_phys, (u_long)mem_ptr_virt); +#endif + break; + } } - } - if (hp100_mode == 3) { /* io mapped forced */ - mem_mapped = 0; - mem_ptr_phys = mem_ptr_virt = NULL; - printk("hp100: Using (slow) programmed i/o mode.\n"); - } - /* Initialise the "private" data structure for this card. */ - if ((dev->priv = kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct hp100_private)); - - lp = (struct hp100_private *) dev->priv; - lp->id = eid; - lp->chip = chip; - lp->mode = hp100_mode; - lp->pci_bus = pci_bus; - lp->bus = bus; - lp->pci_device_fn = pci_device_fn; - lp->priority_tx = hp100_priority_tx; - lp->rx_ratio = hp100_rx_ratio; - lp->mem_ptr_phys = mem_ptr_phys; - lp->mem_ptr_virt = mem_ptr_virt; - hp100_page(ID_MAC_ADDR); - lp->soft_model = hp100_inb(SOFT_MODEL); - lp->mac1_mode = HP100_MAC1MODE3; - lp->mac2_mode = HP100_MAC2MODE3; - - dev->base_addr = ioaddr; - - lp->memory_size = memory_size; - lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ - - /* memory region for programmed i/o */ - request_region(dev->base_addr, HP100_REGION_SIZE, eid->name); - - dev->open = hp100_open; - dev->stop = hp100_close; - - if (lp->mode == 1) /* busmaster */ - dev->hard_start_xmit = hp100_start_xmit_bm; - else - dev->hard_start_xmit = hp100_start_xmit; - - dev->get_stats = hp100_get_stats; - dev->set_multicast_list = &hp100_set_multicast_list; - - /* Ask the card for which IRQ line it is configured */ - hp100_page(HW_MAP); - dev->irq = hp100_inb(IRQ_CHANNEL) & HP100_IRQMASK; - if (dev->irq == 2) - dev->irq = 9; - - if (lp->mode == 1) /* busmaster */ - dev->dma = 4; - - /* Ask the card for its MAC address and store it for later use. */ - hp100_page(ID_MAC_ADDR); - for (i = uc = 0; i < 6; i++) - dev->dev_addr[i] = hp100_inb(LAN_ADDR + i); - - /* Reset statistics (counters) */ - hp100_clear_stats(ioaddr); - - ether_setup(dev); - - /* If busmaster mode is wanted, a dma-capable memory area is needed for - * the rx and tx PDLs - * PCI cards can access the whole PC memory. Therefore GFP_DMA is not - * needed for the allocation of the memory area. - */ - - /* TODO: We do not need this with old cards, where PDLs are stored - * in the cards shared memory area. But currently, busmaster has been - * implemented/tested only with the lassen chip anyway... */ - if (lp->mode == 1) { /* busmaster */ - /* Get physically continous memory for TX & RX PDLs */ - if ((lp->page_vaddr = kmalloc(MAX_RINGSIZE + 0x0f, GFP_KERNEL)) == NULL) - return -ENOMEM; - lp->page_vaddr_algn = ((u_int *) (((u_int) (lp->page_vaddr) + 0x0f) & ~0x0f)); - memset(lp->page_vaddr, 0, MAX_RINGSIZE + 0x0f); + + if(mem_ptr_virt==NULL) /* all ioremap tries failed */ + { + printk("hp100: %s: Failed to ioremap the PCI card memory. Will have to use i/o mapped mode.\n", dev->name); + local_mode=3; + virt_memory_size = 0; + } + } + } + + } + + if(local_mode==3) /* io mapped forced */ + { + mem_mapped = 0; + mem_ptr_phys = mem_ptr_virt = NULL; + printk("hp100: %s: Using (slow) programmed i/o mode.\n", dev->name); + } + + /* Initialise the "private" data structure for this card. */ + if ( (dev->priv=kmalloc(sizeof(struct hp100_private), GFP_KERNEL)) == NULL) + return -ENOMEM; + memset( dev->priv, 0, sizeof(struct hp100_private) ); + + lp = (struct hp100_private *)dev->priv; + lp->id = eid; + lp->chip = chip; + lp->mode = local_mode; + lp->pci_bus = pci_bus; + lp->bus = bus; + lp->pci_device_fn = pci_device_fn; + lp->priority_tx = hp100_priority_tx; + lp->rx_ratio = hp100_rx_ratio; + lp->mem_ptr_phys = mem_ptr_phys; + lp->mem_ptr_virt = mem_ptr_virt; + hp100_page( ID_MAC_ADDR ); + lp->soft_model = hp100_inb( SOFT_MODEL ); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; + memset( &lp->hash_bytes, 0x00, 8 ); + + dev->base_addr = ioaddr; + + lp->memory_size = memory_size; + lp->virt_memory_size = virt_memory_size; + lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ + + /* memory region for programmed i/o */ + request_region( dev->base_addr, HP100_REGION_SIZE, eid->name ); + + dev->open = hp100_open; + dev->stop = hp100_close; + + if (lp->mode==1) /* busmaster */ + dev->hard_start_xmit = hp100_start_xmit_bm; + else + dev->hard_start_xmit = hp100_start_xmit; + + dev->get_stats = hp100_get_stats; + dev->set_multicast_list = &hp100_set_multicast_list; + + /* Ask the card for which IRQ line it is configured */ + hp100_page( HW_MAP ); + dev->irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQMASK; + if ( dev->irq == 2 ) + dev->irq = 9; + + if(lp->mode==1) /* busmaster */ + dev->dma=4; + + /* Ask the card for its MAC address and store it for later use. */ + hp100_page( ID_MAC_ADDR ); + for ( i = uc = 0; i < 6; i++ ) + dev->dev_addr[ i ] = hp100_inb( LAN_ADDR + i ); + + /* Reset statistics (counters) */ + hp100_clear_stats( ioaddr ); + + ether_setup( dev ); + + /* If busmaster mode is wanted, a dma-capable memory area is needed for + * the rx and tx PDLs + * PCI cards can access the whole PC memory. Therefore GFP_DMA is not + * needed for the allocation of the memory area. + */ + + /* TODO: We do not need this with old cards, where PDLs are stored + * in the cards shared memory area. But currently, busmaster has been + * implemented/tested only with the lassen chip anyway... */ + if(lp->mode==1) /* busmaster */ + { + /* Get physically continous memory for TX & RX PDLs */ + if ( (lp->page_vaddr=kmalloc(MAX_RINGSIZE+0x0f,GFP_KERNEL) ) == NULL) + return -ENOMEM; + lp->page_vaddr_algn=((u_int *) ( ((u_int)(lp->page_vaddr)+0x0f) &~0x0f)); + memset(lp->page_vaddr, 0, MAX_RINGSIZE+0x0f); #ifdef HP100_DEBUG_BM - printk("hp100: Reserved DMA memory from 0x%x to 0x%x\n", - (u_int) lp->page_vaddr_algn, - (u_int) lp->page_vaddr_algn + MAX_RINGSIZE); -#endif - lp->rxrcommit = lp->txrcommit = 0; - lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); - lp->txrhead = lp->txrtail = &(lp->txring[0]); - } - /* Initialise the card. */ - /* (I'm not really sure if it's a good idea to do this during probing, but - * like this it's assured that the lan connection type can be sensed - * correctly) - */ - hp100_hwinit(dev); - - /* Try to find out which kind of LAN the card is connected to. */ - lp->lan_type = hp100_sense_lan(dev); - - /* Print out a message what about what we think we have probed. */ - printk("hp100: %s: %s at 0x%x, IRQ %d, ", - dev->name, lp->id->name, ioaddr, dev->irq); - switch (bus) { - case HP100_BUS_EISA: - printk("EISA"); - break; - case HP100_BUS_PCI: - printk("PCI"); - break; - default: - printk("ISA"); - break; - } - printk(" bus, %dk SRAM (rx/tx %d%%).\n", - lp->memory_size >> 10, lp->rx_ratio); + printk("hp100: %s: Reserved DMA memory from 0x%x to 0x%x\n", + dev->name, + (u_int)lp->page_vaddr_algn, + (u_int)lp->page_vaddr_algn+MAX_RINGSIZE); +#endif + lp->rxrcommit = lp->txrcommit = 0; + lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); + lp->txrhead = lp->txrtail = &(lp->txring[0]); + } + + /* Initialise the card. */ + /* (I'm not really sure if it's a good idea to do this during probing, but + * like this it's assured that the lan connection type can be sensed + * correctly) + */ + hp100_hwinit( dev ); + + /* Try to find out which kind of LAN the card is connected to. */ + lp->lan_type = hp100_sense_lan( dev ); + + /* Print out a message what about what we think we have probed. */ + printk( "hp100: %s: %s at 0x%x, IRQ %d, ", + dev->name, lp->id->name, ioaddr, dev->irq ); + switch ( bus ) { + case HP100_BUS_EISA: printk( "EISA" ); break; + case HP100_BUS_PCI: printk( "PCI" ); break; + default: printk( "ISA" ); break; + } + printk( " bus, %dk SRAM (rx/tx %d%%).\n", + lp->memory_size >> 10, lp->rx_ratio ); + + if ( lp->mode==2 ) /* memory mapped */ + { + printk( "hp100: %s: Memory area at 0x%lx-0x%lx", + dev->name,(u_long)mem_ptr_phys, + ((u_long)mem_ptr_phys+(mem_ptr_phys>(u_int *)0x100000?(u_long)lp->memory_size:16*1024))-1 ); + if ( mem_ptr_virt ) + printk( " (virtual base 0x%lx)", (u_long)mem_ptr_virt ); + printk( ".\n" ); + + /* Set for info when doing ifconfig */ + dev->mem_start = (u_long)mem_ptr_phys; + dev->mem_end = (u_long)mem_ptr_phys+(u_long)lp->memory_size; + } + printk( "hp100: %s: ", dev->name ); + if ( lp->lan_type != HP100_LAN_ERR ) + printk( "Adapter is attached to " ); + switch ( lp->lan_type ) { + case HP100_LAN_100: + printk( "100Mb/s Voice Grade AnyLAN network.\n" ); + break; + case HP100_LAN_10: + printk( "10Mb/s network.\n" ); + break; + default: + printk( "Warning! Link down.\n" ); + } - if (lp->mode == 2) { /* memory mapped */ - printk("%s: Memory area at 0x%lx-0x%lx", - dev->name, (u_long) mem_ptr_phys, (u_long) mem_ptr_phys + (u_long) lp->memory_size); - if (mem_ptr_virt) - printk(" (virtual base 0x%lx)", (u_long) mem_ptr_virt); - printk(".\n"); - - /* Set for info when doing ifconfig */ - dev->mem_start = (u_long) mem_ptr_phys; - dev->mem_end = (u_long) mem_ptr_phys + (u_long) lp->memory_size; - } - printk("%s: ", dev->name); - if (lp->lan_type != HP100_LAN_ERR) - printk("Adapter is attached to "); - switch (lp->lan_type) { - case HP100_LAN_100: - printk("100Mb/s Voice Grade AnyLAN network.\n"); - break; - case HP100_LAN_10: - printk("10Mb/s network.\n"); - break; - default: - printk("Warning! Link down.\n"); - } - return 0; + return 0; } - + /* This procedure puts the card into a stable init state */ -static void hp100_hwinit(struct device *dev) +static void hp100_hwinit( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4202, TRACE); - printk("hp100: hwinit\n"); + hp100_outw( 0x4202, TRACE ); + printk("hp100: %s: hwinit\n", dev->name); #endif - /* Initialise the card. -------------------------------------------- */ - - /* Clear all pending Ints and disable Ints */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* clear all pending ints */ - - hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); - - if (lp->mode == 1) { - hp100_BM_shutdown(dev); /* disables BM, puts cascade in reset */ - wait(); - } else { - hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - hp100_cascade_reset(dev, TRUE); - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); - } - - /* Initiate EEPROM reload */ - hp100_load_eeprom(dev); - - wait(); - - /* Go into reset again. */ - hp100_cascade_reset(dev, TRUE); - - /* Set Option Registers to a safe state */ - hp100_outw(HP100_DEBUG_EN | - HP100_RX_HDR | - HP100_EE_EN | - HP100_BM_WRITE | - HP100_BM_READ | HP100_RESET_HB | - HP100_FAKE_INT | - HP100_INT_EN | - HP100_MEM_EN | - HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); - - hp100_outw(HP100_TRI_INT | - HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); - - hp100_outb(HP100_PRIORITY_TX | - HP100_ADV_NXT_PKT | - HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); - - /* TODO: Configure MMU for Ram Test. */ - /* TODO: Ram Test. */ - - /* Re-check if adapter is still at same i/o location */ - /* (If the base i/o in eeprom has been changed but the */ - /* registers had not been changed, a reload of the eeprom */ - /* would move the adapter to the address stored in eeprom */ - - /* TODO: Code to implement. */ - - /* Until here it was code from HWdiscover procedure. */ - /* Next comes code from mmuinit procedure of SCO BM driver which is - * called from HWconfigure in the SCO driver. */ - - /* Initialise MMU, eventually switch on Busmaster Mode, initialise - * multicast filter... - */ - hp100_mmuinit(dev); - - /* We don't turn the interrupts on here - this is done by start_interface. */ - wait(); /* TODO: Do we really need this? */ - - /* Enable Hardware (e.g. unreset) */ - hp100_cascade_reset(dev, FALSE); - - /* ------- initialisation complete ----------- */ - - /* Finally try to log in the Hub if there may be a VG connection. */ - if (lp->lan_type != HP100_LAN_10) - hp100_login_to_vg_hub(dev, FALSE); /* relogin */ + /* Initialise the card. -------------------------------------------- */ + + /* Clear all pending Ints and disable Ints */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* clear all pending ints */ + + hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); + hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW ); + + if(lp->mode==1) + { + hp100_BM_shutdown( dev ); /* disables BM, puts cascade in reset */ + wait(); + } + else + { + hp100_outw( HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); + hp100_cascade_reset( dev, TRUE ); + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN|HP100_TX_EN), MAC_CFG_1); + } + + /* Initiate EEPROM reload */ + hp100_load_eeprom( dev, 0 ); + + wait(); + + /* Go into reset again. */ + hp100_cascade_reset( dev, TRUE ); + + /* Set Option Registers to a safe state */ + hp100_outw( HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | + HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB | + HP100_FAKE_INT | + HP100_INT_EN | + HP100_MEM_EN | + HP100_IO_EN | HP100_RESET_LB, OPTION_LSW); + + hp100_outw( HP100_TRI_INT | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); + + hp100_outb( HP100_PRIORITY_TX | + HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW ); + + /* TODO: Configure MMU for Ram Test. */ + /* TODO: Ram Test. */ + + /* Re-check if adapter is still at same i/o location */ + /* (If the base i/o in eeprom has been changed but the */ + /* registers had not been changed, a reload of the eeprom */ + /* would move the adapter to the address stored in eeprom */ + + /* TODO: Code to implement. */ + + /* Until here it was code from HWdiscover procedure. */ + /* Next comes code from mmuinit procedure of SCO BM driver which is + * called from HWconfigure in the SCO driver. */ + + /* Initialise MMU, eventually switch on Busmaster Mode, initialise + * multicast filter... + */ + hp100_mmuinit( dev ); + + /* We don't turn the interrupts on here - this is done by start_interface. */ + wait(); /* TODO: Do we really need this? */ + + /* Enable Hardware (e.g. unreset) */ + hp100_cascade_reset( dev, FALSE ); + + /* ------- initialisation complete ----------- */ + + /* Finally try to log in the Hub if there may be a VG connection. */ + if( lp->lan_type != HP100_LAN_10 ) + hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ } - + /* * mmuinit - Reinitialise Cascade MMU and MAC settings. * Note: Must already be in reset and leaves card in reset. */ -static void hp100_mmuinit(struct device *dev) +static void hp100_mmuinit( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int i; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4203, TRACE); - printk("hp100: mmuinit\n"); -#endif - -#ifdef HP100_DEBUG - if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { - printk("hp100: Not in reset when entering mmuinit. Fix me.\n"); - return; - } -#endif - - /* Make sure IRQs are masked off and ack'ed. */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ - - /* - * Enable Hardware - * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En - * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable - * - Clear Priority, Advance Pkt and Xmit Cmd - */ - - hp100_outw(HP100_DEBUG_EN | - HP100_RX_HDR | - HP100_EE_EN | HP100_RESET_HB | - HP100_IO_EN | - HP100_FAKE_INT | - HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - - hp100_outw(HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); - - if (lp->mode == 1) { /* busmaster */ - hp100_outw(HP100_BM_WRITE | - HP100_BM_READ | - HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); - } else if (lp->mode == 2) { /* memory mapped */ - hp100_outw(HP100_BM_WRITE | - HP100_BM_READ | HP100_RESET_HB, OPTION_LSW); - hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); - hp100_outw(HP100_MEM_EN | HP100_SET_LB, OPTION_LSW); - hp100_outw(HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - } else if (lp->mode == 3) { /* i/o mapped mode */ - hp100_outw(HP100_MMAP_DIS | HP100_SET_HB | - HP100_IO_EN | HP100_SET_LB, OPTION_LSW); - } - hp100_page(HW_MAP); - hp100_outb(0, EARLYRXCFG); - hp100_outw(0, EARLYTXCFG); - - /* - * Enable Bus Master mode - */ - if (lp->mode == 1) { /* busmaster */ - /* Experimental: Set some PCI configuration bits */ - hp100_page(HW_MAP); - hp100_andb(~HP100_PDL_USE3, MODECTRL1); /* BM engine read maximum */ - hp100_andb(~HP100_TX_DUALQ, MODECTRL1); /* No Queue for Priority TX */ - - /* PCI Bus failures should result in a Misc. Interrupt */ - hp100_orb(HP100_EN_BUS_FAIL, MODECTRL2); - - hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW); - hp100_page(HW_MAP); - /* Use Burst Mode and switch on PAGE_CK */ - hp100_orb(HP100_BM_BURST_RD | - HP100_BM_BURST_WR, BM); - if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA)) - hp100_orb(HP100_BM_PAGE_CK, BM); - hp100_orb(HP100_BM_MASTER, BM); - } else { /* not busmaster */ - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM); - } - - /* - * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs - */ - hp100_page(MMU_CFG); - if (lp->mode == 1) { /* only needed for Busmaster */ - int xmit_stop, recv_stop; - - if ((lp->chip == HP100_CHIPID_RAINIER) || (lp->chip == HP100_CHIPID_SHASTA)) { - int pdl_stop; - - /* - * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and - * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded - * to the next higher 1k boundary) bytes for the rx-pdl's - * Note: For non-etr chips the transmit stop register must be - * programmed on a 1k boundary, i.e. bits 9:0 must be zero. - */ - pdl_stop = lp->memory_size; - xmit_stop = (pdl_stop - 508 * (MAX_RX_PDL) - 16) & ~(0x03ff); - recv_stop = (xmit_stop * (lp->rx_ratio) / 100) & ~(0x03ff); - hp100_outw((pdl_stop >> 4) - 1, PDL_MEM_STOP); + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int i; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4203, TRACE ); + printk("hp100: %s: mmuinit\n",dev->name); +#endif + +#ifdef HP100_DEBUG + if( 0!=(hp100_inw(OPTION_LSW)&HP100_HW_RST) ) + { + printk("hp100: %s: Not in reset when entering mmuinit. Fix me.\n",dev->name); + return; + } +#endif + + /* Make sure IRQs are masked off and ack'ed. */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ + + /* + * Enable Hardware + * - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En + * - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable + * - Clear Priority, Advance Pkt and Xmit Cmd + */ + + hp100_outw( HP100_DEBUG_EN | + HP100_RX_HDR | + HP100_EE_EN | HP100_RESET_HB | + HP100_IO_EN | + HP100_FAKE_INT | + HP100_INT_EN | HP100_RESET_LB, OPTION_LSW ); + + hp100_outw( HP100_TRI_INT | HP100_SET_HB, OPTION_LSW); + + if(lp->mode==1) /* busmaster */ + { + hp100_outw( HP100_BM_WRITE | + HP100_BM_READ | + HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); + } + else if(lp->mode==2) /* memory mapped */ + { + hp100_outw( HP100_BM_WRITE | + HP100_BM_READ | HP100_RESET_HB, OPTION_LSW ); + hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW ); + hp100_outw( HP100_MEM_EN | HP100_SET_LB, OPTION_LSW ); + hp100_outw( HP100_IO_EN | HP100_SET_LB, OPTION_LSW ); + } + else if( lp->mode==3 ) /* i/o mapped mode */ + { + hp100_outw( HP100_MMAP_DIS | HP100_SET_HB | + HP100_IO_EN | HP100_SET_LB, OPTION_LSW ); + } + + hp100_page( HW_MAP ); + hp100_outb( 0, EARLYRXCFG ); + hp100_outw( 0, EARLYTXCFG ); + + /* + * Enable Bus Master mode + */ + if(lp->mode==1) /* busmaster */ + { + /* Experimental: Set some PCI configuration bits */ + hp100_page( HW_MAP ); + hp100_andb( ~HP100_PDL_USE3, MODECTRL1 ); /* BM engine read maximum */ + hp100_andb( ~HP100_TX_DUALQ, MODECTRL1 ); /* No Queue for Priority TX */ + + /* PCI Bus failures should result in a Misc. Interrupt */ + hp100_orb( HP100_EN_BUS_FAIL, MODECTRL2); + + hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_SET_HB, OPTION_LSW ); + hp100_page( HW_MAP ); + /* Use Burst Mode and switch on PAGE_CK */ + hp100_orb( HP100_BM_BURST_RD | + HP100_BM_BURST_WR, BM); + if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA)) + hp100_orb( HP100_BM_PAGE_CK, BM ); + hp100_orb( HP100_BM_MASTER, BM ); + } + else /* not busmaster */ + { + hp100_page(HW_MAP); + hp100_andb(~HP100_BM_MASTER, BM ); + } + + /* + * Divide card memory into regions for Rx, Tx and, if non-ETR chip, PDLs + */ + hp100_page( MMU_CFG ); + if(lp->mode==1) /* only needed for Busmaster */ + { + int xmit_stop, recv_stop; + + if((lp->chip==HP100_CHIPID_RAINIER)||(lp->chip==HP100_CHIPID_SHASTA)) + { + int pdl_stop; + + /* + * Each pdl is 508 bytes long. (63 frags * 4 bytes for address and + * 4 bytes for for header). We will leave NUM_RXPDLS * 508 (rounded + * to the next higher 1k boundary) bytes for the rx-pdl's + * Note: For non-etr chips the transmit stop register must be + * programmed on a 1k boundary, i.e. bits 9:0 must be zero. + */ + pdl_stop = lp->memory_size; + xmit_stop = ( pdl_stop-508*(MAX_RX_PDL)-16 )& ~(0x03ff); + recv_stop = ( xmit_stop * (lp->rx_ratio)/100 ) &~(0x03ff); + hp100_outw( (pdl_stop>>4)-1, PDL_MEM_STOP ); #ifdef HP100_DEBUG_BM - printk("hp100: PDL_STOP = 0x%x\n", pdl_stop); + printk("hp100: %s: PDL_STOP = 0x%x\n", dev->name, pdl_stop); #endif - } else { /* ETR chip (Lassen) in busmaster mode */ - xmit_stop = (lp->memory_size) - 1; - recv_stop = ((lp->memory_size * lp->rx_ratio) / 100) & ~(0x03ff); - } + } + else /* ETR chip (Lassen) in busmaster mode */ + { + xmit_stop = ( lp->memory_size ) - 1; + recv_stop = ( ( lp->memory_size * lp->rx_ratio ) / 100 ) & ~(0x03ff); + } - hp100_outw(xmit_stop >> 4, TX_MEM_STOP); - hp100_outw(recv_stop >> 4, RX_MEM_STOP); + hp100_outw( xmit_stop>>4 , TX_MEM_STOP ); + hp100_outw( recv_stop>>4 , RX_MEM_STOP ); #ifdef HP100_DEBUG_BM - printk("hp100: TX_STOP = 0x%x\n", xmit_stop >> 4); - printk("hp100: RX_STOP = 0x%x\n", recv_stop >> 4); + printk("hp100: %s: TX_STOP = 0x%x\n",dev->name,xmit_stop>>4); + printk("hp100: %s: RX_STOP = 0x%x\n",dev->name,recv_stop>>4); #endif - } else { /* Slave modes (memory mapped and programmed io) */ - hp100_outw((((lp->memory_size * lp->rx_ratio) / 100) >> 4), RX_MEM_STOP); - hp100_outw(((lp->memory_size - 1) >> 4), TX_MEM_STOP); -#ifdef HP100_DEBUG - printk("hp100: TX_MEM_STOP: 0x%x\n", hp100_inw(TX_MEM_STOP)); - printk("hp100: RX_MEM_STOP: 0x%x\n", hp100_inw(RX_MEM_STOP)); -#endif - } - - /* Write MAC address into page 1 */ - hp100_page(MAC_ADDRESS); - for (i = 0; i < 6; i++) - hp100_outb(dev->dev_addr[i], MAC_ADDR + i); - - /* Zero the multicast hash registers */ - for (i = 0; i < 8; i++) - hp100_outb(0x0, HASH_BYTE0 + i); - - /* Set up MAC defaults */ - hp100_page(MAC_CTRL); - - /* Go to LAN Page and zero all filter bits */ - /* Zero accept error, accept multicast, accept broadcast and accept */ - /* all directed packet bits */ - hp100_andb(~(HP100_RX_EN | - HP100_TX_EN | - HP100_ACC_ERRORED | - HP100_ACC_MC | - HP100_ACC_BC | - HP100_ACC_PHY), MAC_CFG_1); - - hp100_outb(0x00, MAC_CFG_2); - - /* Zero the frame format bit. This works around a training bug in the */ - /* new hubs. */ - hp100_outb(0x00, VG_LAN_CFG_2); /* (use 802.3) */ - - if (lp->priority_tx) - hp100_outb(HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW); - else - hp100_outb(HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW); - - hp100_outb(HP100_ADV_NXT_PKT | - HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW); - - /* If busmaster, initialize the PDLs */ - if (lp->mode == 1) - hp100_init_pdls(dev); - - /* Go to performance page and initalize isr and imr registers */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ + } + else /* Slave modes (memory mapped and programmed io) */ + { + hp100_outw( (((lp->memory_size*lp->rx_ratio)/100)>>4), RX_MEM_STOP ); + hp100_outw( ((lp->memory_size - 1 )>>4), TX_MEM_STOP ); +#ifdef HP100_DEBUG + printk("hp100: %s: TX_MEM_STOP: 0x%x\n", dev->name,hp100_inw(TX_MEM_STOP)); + printk("hp100: %s: RX_MEM_STOP: 0x%x\n", dev->name,hp100_inw(RX_MEM_STOP)); +#endif + } + + /* Write MAC address into page 1 */ + hp100_page( MAC_ADDRESS ); + for ( i = 0; i < 6; i++ ) + hp100_outb( dev->dev_addr[ i ], MAC_ADDR + i ); + + /* Zero the multicast hash registers */ + for ( i = 0; i < 8; i++ ) + hp100_outb( 0x0, HASH_BYTE0 + i ); + + /* Set up MAC defaults */ + hp100_page( MAC_CTRL ); + + /* Go to LAN Page and zero all filter bits */ + /* Zero accept error, accept multicast, accept broadcast and accept */ + /* all directed packet bits */ + hp100_andb( ~(HP100_RX_EN| + HP100_TX_EN| + HP100_ACC_ERRORED| + HP100_ACC_MC| + HP100_ACC_BC| + HP100_ACC_PHY), MAC_CFG_1 ); + + hp100_outb( 0x00, MAC_CFG_2 ); + + /* Zero the frame format bit. This works around a training bug in the */ + /* new hubs. */ + hp100_outb( 0x00, VG_LAN_CFG_2); /* (use 802.3) */ + + if(lp->priority_tx) + hp100_outb( HP100_PRIORITY_TX | HP100_SET_LB, OPTION_MSW ); + else + hp100_outb( HP100_PRIORITY_TX | HP100_RESET_LB, OPTION_MSW ); + + hp100_outb( HP100_ADV_NXT_PKT | + HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW ); + + /* If busmaster, initialize the PDLs */ + if(lp->mode==1) + hp100_init_pdls( dev ); + + /* Go to performance page and initalize isr and imr registers */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ } - + /* * open/close functions */ -static int hp100_open(struct device *dev) +static int hp100_open( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; + int ioaddr=dev->base_addr; #endif #ifdef HP100_DEBUG_B - hp100_outw(0x4204, TRACE); - printk("hp100: open\n"); + hp100_outw( 0x4204, TRACE ); + printk("hp100: %s: open\n",dev->name); #endif + + /* New: if bus is PCI or EISA, interrupts might be shared interrupts */ + if ( request_irq(dev->irq, hp100_interrupt, + lp->bus==HP100_BUS_PCI||lp->bus==HP100_BUS_EISA?SA_SHIRQ:SA_INTERRUPT, + lp->id->name, dev)) + { + printk( "hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq ); + return -EAGAIN; + } - /* New: if bus is PCI or EISA, interrupts might be shared interrupts */ - if ((lp->bus == HP100_BUS_PCI) || (lp->bus == HP100_BUS_EISA)) { - if (request_irq(dev->irq, hp100_interrupt, SA_SHIRQ, lp->id->name, dev)) { - printk("%s: unable to get IRQ %d\n", dev->name, dev->irq); - return -EAGAIN; - } - } else if (request_irq(dev->irq, hp100_interrupt, SA_INTERRUPT, lp->id->name, dev)) { - printk("%s: unable to get IRQ %d\n", dev->name, dev->irq); - return -EAGAIN; - } - MOD_INC_USE_COUNT; - - dev->tbusy = 0; - dev->trans_start = jiffies; - dev->interrupt = 0; - dev->start = 1; + MOD_INC_USE_COUNT; - lp->lan_type = hp100_sense_lan(dev); - lp->mac1_mode = HP100_MAC1MODE3; - lp->mac2_mode = HP100_MAC2MODE3; + dev->tbusy = 0; + dev->trans_start = jiffies; + dev->interrupt = 0; + dev->start = 1; - hp100_stop_interface(dev); + lp->lan_type = hp100_sense_lan( dev ); + lp->mac1_mode = HP100_MAC1MODE3; + lp->mac2_mode = HP100_MAC2MODE3; + memset( &lp->hash_bytes, 0x00, 8 ); - hp100_hwinit(dev); + hp100_stop_interface( dev ); + + hp100_hwinit( dev ); - hp100_start_interface(dev); /* sets mac modes, enables interrupts */ + hp100_start_interface( dev ); /* sets mac modes, enables interrupts */ - return 0; + return 0; } - + /* The close function is called when the interface is to be brought down */ -static int hp100_close(struct device *dev) +static int hp100_close( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4205, TRACE); - printk("hp100:close\n"); + hp100_outw( 0x4205, TRACE ); + printk("hp100: %s: close\n", dev->name); #endif - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all IRQs */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all IRQs */ - hp100_stop_interface(dev); + hp100_stop_interface( dev ); - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status=hp100_login_to_vg_hub( dev, FALSE ); - dev->tbusy = 1; - dev->start = 0; + dev->tbusy = 1; + dev->start = 0; + + free_irq( dev->irq, dev ); + +#ifdef HP100_DEBUG + printk( "hp100: %s: close LSW = 0x%x\n", dev->name, hp100_inw(OPTION_LSW) ); +#endif - if ((lp->bus == HP100_BUS_PCI) || (lp->bus == HP100_BUS_EISA)) - free_irq(dev->irq, dev); - else - free_irq(dev->irq, NULL); - MOD_DEC_USE_COUNT; - return 0; + MOD_DEC_USE_COUNT; + return 0; } - + /* * Configure the PDL Rx rings and LAN */ -static void hp100_init_pdls(struct device *dev) +static void hp100_init_pdls( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; - hp100_ring_t *ringptr; - u_int *pageptr; - int i; - -#ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ringptr; + u_int *pageptr; + int i; + +#ifdef HP100_DEBUG_B + int ioaddr = dev->base_addr; #endif #ifdef HP100_DEBUG_B - hp100_outw(0x4206, TRACE); - printk("hp100: init pdls\n"); -#endif - - if (0 == lp->page_vaddr_algn) - printk("hp100: Warning: lp->page_vaddr_algn not initialised!\n"); - else { - /* pageptr shall point into the DMA accessible memory region */ - /* we use this pointer to status the upper limit of allocated */ - /* memory in the allocated page. */ - /* note: align the pointers to the pci cache line size */ - memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ - pageptr = lp->page_vaddr_algn; - - lp->rxrcommit = 0; - ringptr = lp->rxrhead = lp->rxrtail = &(lp->rxring[0]); - - /* Initialise Rx Ring */ - for (i = MAX_RX_PDL - 1; i >= 0; i--) { - lp->rxring[i].next = ringptr; - ringptr = &(lp->rxring[i]); - pageptr += hp100_init_rxpdl(ringptr, pageptr); - } - - /* Initialise Tx Ring */ - lp->txrcommit = 0; - ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); - for (i = MAX_TX_PDL - 1; i >= 0; i--) { - lp->txring[i].next = ringptr; - ringptr = &(lp->txring[i]); - pageptr += hp100_init_txpdl(ringptr, pageptr); - } - } + hp100_outw( 0x4206, TRACE ); + printk("hp100: %s: init pdls\n", dev->name); +#endif + + if(0==lp->page_vaddr_algn) + printk("hp100: %s: Warning: lp->page_vaddr_algn not initialised!\n",dev->name); + else + { + /* pageptr shall point into the DMA accessible memory region */ + /* we use this pointer to status the upper limit of allocated */ + /* memory in the allocated page. */ + /* note: align the pointers to the pci cache line size */ + memset(lp->page_vaddr_algn, 0, MAX_RINGSIZE); /* Zero Rx/Tx ring page */ + pageptr=lp->page_vaddr_algn; + + lp->rxrcommit =0; + ringptr = lp->rxrhead = lp-> rxrtail = &(lp->rxring[0]); + + /* Initialise Rx Ring */ + for (i=MAX_RX_PDL-1; i>=0; i--) + { + lp->rxring[i].next = ringptr; + ringptr=&(lp->rxring[i]); + pageptr+=hp100_init_rxpdl(dev, ringptr, pageptr); + } + + /* Initialise Tx Ring */ + lp->txrcommit = 0; + ringptr = lp->txrhead = lp->txrtail = &(lp->txring[0]); + for (i=MAX_TX_PDL-1; i>=0; i--) + { + lp->txring[i].next = ringptr; + ringptr=&(lp->txring[i]); + pageptr+=hp100_init_txpdl(dev, ringptr, pageptr); + } + } } - + /* These functions "format" the entries in the pdl structure */ /* They return how much memory the fragments need. */ -static int hp100_init_rxpdl(register hp100_ring_t * ringptr, register u32 * pdlptr) +static int hp100_init_rxpdl( struct device *dev, register hp100_ring_t *ringptr, register u32 *pdlptr ) { - /* pdlptr is starting adress for this pdl */ + /* pdlptr is starting adress for this pdl */ - if (0 != (((unsigned) pdlptr) & 0xf)) - printk("hp100: Init rxpdl: Unaligned pdlptr 0x%x.\n", (unsigned) pdlptr); + if( 0!=( ((unsigned)pdlptr) & 0xf) ) + printk("hp100: %s: Init rxpdl: Unaligned pdlptr 0x%x.\n",dev->name,(unsigned)pdlptr); - ringptr->pdl = pdlptr + 1; - ringptr->pdl_paddr = virt_to_bus(pdlptr + 1); - ringptr->skb = (void *) NULL; + ringptr->pdl = pdlptr+1; + ringptr->pdl_paddr = virt_to_bus(pdlptr+1); + ringptr->skb = (void *) NULL; - /* - * Write address and length of first PDL Fragment (which is used for - * storing the RX-Header - * We use the 4 bytes _before_ the PDH in the pdl memory area to - * store this information. (PDH is at offset 0x04) - */ - /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ + /* + * Write address and length of first PDL Fragment (which is used for + * storing the RX-Header + * We use the 4 bytes _before_ the PDH in the pdl memory area to + * store this information. (PDH is at offset 0x04) + */ + /* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */ - *(pdlptr + 2) = (u_int) virt_to_bus(pdlptr); /* Address Frag 1 */ - *(pdlptr + 3) = 4; /* Length Frag 1 */ + *(pdlptr+2) =(u_int) virt_to_bus(pdlptr); /* Address Frag 1 */ + *(pdlptr+3) = 4; /* Length Frag 1 */ - return ((((MAX_RX_FRAG * 2 + 2) + 3) / 4) * 4); + return( ( ((MAX_RX_FRAG*2+2)+3) /4)*4 ); } -static int hp100_init_txpdl(register hp100_ring_t * ringptr, register u32 * pdlptr) +static int hp100_init_txpdl( struct device *dev, register hp100_ring_t *ringptr, register u32 *pdlptr ) { - if (0 != (((unsigned) pdlptr) & 0xf)) - printk("hp100: Init txpdl: Unaligned pdlptr 0x%x.\n", (unsigned) pdlptr); - - ringptr->pdl = pdlptr; /* +1; */ - ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */ - ringptr->skb = (void *) NULL; + if( 0!=( ((unsigned)pdlptr) & 0xf) ) + printk("hp100: %s: Init txpdl: Unaligned pdlptr 0x%x.\n",dev->name,(unsigned) pdlptr); - return ((((MAX_TX_FRAG * 2 + 2) + 3) / 4) * 4); + ringptr->pdl = pdlptr; /* +1; */ + ringptr->pdl_paddr = virt_to_bus(pdlptr); /* +1 */ + ringptr->skb = (void *) NULL; + + return((((MAX_TX_FRAG*2+2)+3)/4)*4); } - + /* * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes * for possible odd word alignment rounding up to next dword and set PDL @@ -1119,77 +1309,80 @@ * Returns: 0 if unable to allocate skb_buff * 1 if successful */ -int hp100_build_rx_pdl(hp100_ring_t * ringptr, struct device *dev) +int hp100_build_rx_pdl( hp100_ring_t *ringptr, struct device *dev ) { #ifdef HP100_DEBUG_B - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; #endif #ifdef HP100_DEBUG_BM - u_int *p; + u_int *p; #endif #ifdef HP100_DEBUG_B - hp100_outw(0x4207, TRACE); - printk("hp100: build rx pdl\n"); + hp100_outw( 0x4207, TRACE ); + printk("hp100: %s: build rx pdl\n", dev->name); #endif - /* Allocate skb buffer of maximum size */ - /* Note: This depends on the alloc_skb functions allocating more - * space than requested, i.e. aligning to 16bytes */ - - ringptr->skb = dev_alloc_skb(((MAX_ETHER_SIZE + 2 + 3) / 4) * 4); - - if (NULL != ringptr->skb) { - /* - * Reserve 2 bytes at the head of the buffer to land the IP header - * on a long word boundary (According to the Network Driver section - * in the Linux KHG, this should help to increase performance.) - */ - skb_reserve(ringptr->skb, 2); - - ringptr->skb->dev = dev; - ringptr->skb->data = (u_char *) skb_put(ringptr->skb, MAX_ETHER_SIZE); - - /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ - /* Note: 1st Fragment is used for the 4 byte packet status - * (receive header). Its PDL entries are set up by init_rxpdl. So - * here we only have to set up the PDL fragment entries for the data - * part. Those 4 bytes will be stored in the DMA memory region - * directly before the PDL. - */ + /* Allocate skb buffer of maximum size */ + /* Note: This depends on the alloc_skb functions allocating more + * space than requested, i.e. aligning to 16bytes */ + + ringptr->skb = dev_alloc_skb( ((MAX_ETHER_SIZE+2+3)/4)*4 ); + + if(NULL!=ringptr->skb) + { + /* + * Reserve 2 bytes at the head of the buffer to land the IP header + * on a long word boundary (According to the Network Driver section + * in the Linux KHG, this should help to increase performance.) + */ + skb_reserve(ringptr->skb, 2); + + ringptr->skb->dev=dev; + ringptr->skb->data=(u_char *)skb_put(ringptr->skb, MAX_ETHER_SIZE ); + + /* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */ + /* Note: 1st Fragment is used for the 4 byte packet status + * (receive header). Its PDL entries are set up by init_rxpdl. So + * here we only have to set up the PDL fragment entries for the data + * part. Those 4 bytes will be stored in the DMA memory region + * directly before the PDL. + */ #ifdef HP100_DEBUG_BM - printk("hp100: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", - (u_int) ringptr->pdl, - ((MAX_ETHER_SIZE + 2 + 3) / 4) * 4, - (unsigned int) ringptr->skb->data); + printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", + dev->name, + (u_int) ringptr->pdl, + ((MAX_ETHER_SIZE+2+3)/4)*4, + (unsigned int) ringptr->skb->data); #endif - ringptr->pdl[0] = 0x00020000; /* Write PDH */ - ringptr->pdl[3] = ((u_int) virt_to_bus(ringptr->skb->data)); - ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ - + ringptr->pdl[0] = 0x00020000; /* Write PDH */ + ringptr->pdl[3] = ((u_int)virt_to_bus(ringptr->skb->data)); + ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */ + #ifdef HP100_DEBUG_BM - for (p = (ringptr->pdl); p < (ringptr->pdl + 5); p++) - printk("Adr 0x%.8x = 0x%.8x\n", (u_int) p, (u_int) * p); + for(p=(ringptr->pdl); p<(ringptr->pdl+5); p++) + printk("hp100: %s: Adr 0x%.8x = 0x%.8x\n",dev->name,(u_int) p,(u_int) *p ); #endif - return (1); - } - /* else: */ - /* alloc_skb failed (no memory) -> still can receive the header - * fragment into PDL memory. make PDL safe by clearing msgptr and - * making the PDL only 1 fragment (i.e. the 4 byte packet status) - */ + return(1); + } + /* else: */ + /* alloc_skb failed (no memory) -> still can receive the header + * fragment into PDL memory. make PDL safe by clearing msgptr and + * making the PDL only 1 fragment (i.e. the 4 byte packet status) + */ #ifdef HP100_DEBUG_BM - printk("hp100: build_rx_pdl: PDH@0x%x, No space for skb.\n", - (u_int) ringptr->pdl); + printk("hp100: %s: build_rx_pdl: PDH@0x%x, No space for skb.\n", + dev->name, + (u_int) ringptr->pdl); #endif - ringptr->pdl[0] = 0x00010000; /* PDH: Count=1 Fragment */ + ringptr->pdl[0]=0x00010000; /* PDH: Count=1 Fragment */ - return (0); + return(0); } - + /* * hp100_rxfill - attempt to fill the Rx Ring will empty skb's * @@ -1200,246 +1393,279 @@ * b. Put the physical address of the buffer into the PDL. * c. Output physical address of PDL to adapter. */ -static void hp100_rxfill(struct device *dev) +static void hp100_rxfill( struct device *dev ) { - int ioaddr = dev->base_addr; + int ioaddr=dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - hp100_ring_t *ringptr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ringptr; #ifdef HP100_DEBUG_B - hp100_outw(0x4208, TRACE); - printk("hp100: rxfill\n"); -#endif - - hp100_page(PERFORMANCE); - - while (lp->rxrcommit < MAX_RX_PDL) { - /* - ** Attempt to get a buffer and build a Rx PDL. - */ - ringptr = lp->rxrtail; - if (0 == hp100_build_rx_pdl(ringptr, dev)) { - return; /* None available, return */ - } - /* Hand this PDL over to the card */ - /* Note: This needs performance page selected! */ + hp100_outw( 0x4208, TRACE ); + printk("hp100: %s: rxfill\n",dev->name); +#endif + + hp100_page( PERFORMANCE ); + + while (lp->rxrcommit < MAX_RX_PDL) + { + /* + ** Attempt to get a buffer and build a Rx PDL. + */ + ringptr = lp->rxrtail; + if (0 == hp100_build_rx_pdl( ringptr, dev )) + { + return; /* None available, return */ + } + + /* Hand this PDL over to the card */ + /* Note: This needs performance page selected! */ #ifdef HP100_DEBUG_BM - printk("hp100: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", - lp->rxrcommit, - (u_int) ringptr->pdl, - (u_int) ringptr->pdl_paddr, - (u_int) ringptr->pdl[3]); + printk("hp100: %s: rxfill: Hand to card: pdl #%d @0x%x phys:0x%x, buffer: 0x%x\n", + dev->name, + lp->rxrcommit, + (u_int)ringptr->pdl, + (u_int)ringptr->pdl_paddr, + (u_int)ringptr->pdl[3]); #endif - hp100_outl((u32) ringptr->pdl_paddr, RX_PDA); - - lp->rxrcommit += 1; - lp->rxrtail = ringptr->next; - } + hp100_outl( (u32)ringptr->pdl_paddr, RX_PDA); + + lp->rxrcommit += 1; + lp->rxrtail = ringptr->next; + } } - + /* * BM_shutdown - shutdown bus mastering and leave chip in reset state */ -static void hp100_BM_shutdown(struct device *dev) +static void hp100_BM_shutdown( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - unsigned long time; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4209, TRACE); - printk("hp100: bm shutdown\n"); -#endif - - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* Ack all ints */ - - /* Ensure Interrupts are off */ - hp100_outw(HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - - /* Disable all MAC activity */ - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ - - /* If cascade MMU is not already in reset */ - if (0 != (hp100_inw(OPTION_LSW) & HP100_HW_RST)) { - /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so - * MMU pointers will not be reset out from underneath - */ - hp100_page(MAC_CTRL); - for (time = 0; time < 5000; time++) { - if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == - (HP100_TX_IDLE | HP100_RX_IDLE)) - break; - } - - /* Shutdown algorithm depends on the generation of Cascade */ - if (lp->chip == HP100_CHIPID_LASSEN) { /* ETR shutdown/reset */ - /* Disable Busmaster mode and wait for bit to go to zero. */ - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM); - /* 100 ms timeout */ - for (time = 0; time < 32000; time++) { - if (0 == (hp100_inb(BM) & HP100_BM_MASTER)) - break; - } - } else { /* Shasta or Rainier Shutdown/Reset */ - /* To ensure all bus master inloading activity has ceased, - * wait for no Rx PDAs or no Rx packets on card. - */ - hp100_page(PERFORMANCE); - /* 100 ms timeout */ - for (time = 0; time < 10000; time++) { - /* RX_PDL: PDLs not executed. */ - /* RX_PKT_CNT: RX'd packets on card. */ - if ((hp100_inb(RX_PDL) == 0) && - (hp100_inb(RX_PKT_CNT) == 0)) - break; - } - - if (time >= 10000) - printk("hp100: BM shutdown error.\n"); - - /* To ensure all bus master outloading activity has ceased, - * wait until the Tx PDA count goes to zero or no more Tx space - * available in the Tx region of the card. - */ - /* 100 ms timeout */ - for (time = 0; time < 10000; time++) { - if ((0 == hp100_inb(TX_PKT_CNT)) && - (0 != (hp100_inb(TX_MEM_FREE) & HP100_AUTO_COMPARE))) - break; - } - - /* Disable Busmaster mode */ - hp100_page(HW_MAP); - hp100_andb(~HP100_BM_MASTER, BM); - } /* end of shutdown procedure for non-etr parts */ - - hp100_cascade_reset(dev, TRUE); - } - hp100_page(PERFORMANCE); - hp100_outw(HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW); - /* Busmaster mode should be shut down now. */ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + unsigned long time; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4209, TRACE ); + printk("hp100: %s: bm shutdown\n",dev->name); +#endif + + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* Ack all ints */ + + /* Ensure Interrupts are off */ + hp100_outw( HP100_INT_EN | HP100_RESET_LB , OPTION_LSW ); + + /* Disable all MAC activity */ + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ + + /* If cascade MMU is not already in reset */ + if (0 != (hp100_inw(OPTION_LSW)&HP100_HW_RST) ) + { + /* Wait 1.3ms (10Mb max packet time) to ensure MAC is idle so + * MMU pointers will not be reset out from underneath + */ + hp100_page( MAC_CTRL ); + for(time=0; time<5000; time++) + { + if( (hp100_inb(MAC_CFG_1)&(HP100_TX_IDLE|HP100_RX_IDLE))== + (HP100_TX_IDLE|HP100_RX_IDLE) ) break; + } + + /* Shutdown algorithm depends on the generation of Cascade */ + if( lp->chip==HP100_CHIPID_LASSEN ) + { /* ETR shutdown/reset */ + /* Disable Busmaster mode and wait for bit to go to zero. */ + hp100_page(HW_MAP); + hp100_andb( ~HP100_BM_MASTER, BM ); + /* 100 ms timeout */ + for(time=0; time<32000; time++) + { + if ( 0 == (hp100_inb( BM ) & HP100_BM_MASTER) ) break; + } + } + else + { /* Shasta or Rainier Shutdown/Reset */ + /* To ensure all bus master inloading activity has ceased, + * wait for no Rx PDAs or no Rx packets on card. + */ + hp100_page( PERFORMANCE ); + /* 100 ms timeout */ + for(time=0; time<10000; time++) + { + /* RX_PDL: PDLs not executed. */ + /* RX_PKT_CNT: RX'd packets on card. */ + if ( (hp100_inb( RX_PDL ) == 0) && + (hp100_inb( RX_PKT_CNT ) == 0) ) break; + } + + if(time>=10000) + printk("hp100: %s: BM shutdown error.\n", dev->name); + + /* To ensure all bus master outloading activity has ceased, + * wait until the Tx PDA count goes to zero or no more Tx space + * available in the Tx region of the card. + */ + /* 100 ms timeout */ + for(time=0; time<10000; time++) { + if ( (0 == hp100_inb( TX_PKT_CNT )) && + (0 != (hp100_inb( TX_MEM_FREE )&HP100_AUTO_COMPARE))) break; + } + + /* Disable Busmaster mode */ + hp100_page(HW_MAP); + hp100_andb( ~HP100_BM_MASTER, BM ); + } /* end of shutdown procedure for non-etr parts */ + + hp100_cascade_reset( dev, TRUE ); + } + hp100_page( PERFORMANCE ); + /* hp100_outw( HP100_BM_READ | HP100_BM_WRITE | HP100_RESET_HB, OPTION_LSW ); */ + /* Busmaster mode should be shut down now. */ } - + /* * transmit functions */ /* tx function for busmaster mode */ -static int hp100_start_xmit_bm(struct sk_buff *skb, struct device *dev) +static int hp100_start_xmit_bm( struct sk_buff *skb, struct device *dev ) { - int i, ok_flag; - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - hp100_ring_t *ringptr; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4210, TRACE); - printk("hp100: start_xmit_bm\n"); -#endif - - /* Get Tx ring tail pointer */ - if (lp->txrtail->next == lp->txrhead) { - /* No memory. */ -#ifdef HP100_DEBUG - printk("hp100: start_xmit_bm: No TX PDL available.\n"); -#endif - /* not waited long enough since last tx? */ - if (jiffies - dev->trans_start < HZ / 10) - return -EAGAIN; - - if (lp->lan_type < 0) { /* no LAN type detected yet? */ - hp100_stop_interface(dev); - if ((lp->lan_type = hp100_sense_lan(dev)) < 0) { - printk("%s: no connection found - check wire\n", dev->name); - hp100_start_interface(dev); /* 10Mb/s RX pkts maybe handled */ - return -EIO; - } - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); /* relogin */ - hp100_start_interface(dev); - } - if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) - /* we have a 100Mb/s adapter but it isn't connected to hub */ - { - printk("%s: login to 100Mb/s hub retry\n", dev->name); - hp100_stop_interface(dev); - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); - hp100_start_interface(dev); - } else { - hp100_ints_off(); - i = hp100_sense_lan(dev); - hp100_page(PERFORMANCE); - hp100_ints_on(); - if (i == HP100_LAN_ERR) - printk("%s: link down detected\n", dev->name); - else if (lp->lan_type != i) { /* cable change! */ - /* it's very hard - all network setting must be changed!!! */ - printk("%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); - lp->lan_type = i; - hp100_stop_interface(dev); - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); - hp100_start_interface(dev); - } else { - printk("%s: interface reset\n", dev->name); - hp100_stop_interface(dev); - hp100_start_interface(dev); - } - } - - dev->trans_start = jiffies; - return -EAGAIN; - } - /* - * we have to turn int's off before modifying this, otherwise - * a tx_pdl_cleanup could occur at the same time - */ - cli(); - ringptr = lp->txrtail; - lp->txrtail = ringptr->next; - - /* Check whether packet has minimal packet size */ - ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; - i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; - - ringptr->skb = skb; - ringptr->pdl[0] = ((1 << 16) | i); /* PDH: 1 Fragment & length */ - ringptr->pdl[1] = (u32) virt_to_bus(skb->data); /* 1st Frag: Adr. of data */ - if (lp->chip == HP100_CHIPID_SHASTA) { - /* TODO:Could someone who has the EISA card please check if this works? */ - ringptr->pdl[2] = i; - } else { /* Lassen */ - /* In the PDL, don't use the padded size but the real packet size: */ - ringptr->pdl[2] = skb->len; /* 1st Frag: Length of frag */ - } - - /* Hand this PDL to the card. */ - hp100_outl(ringptr->pdl_paddr, TX_PDA_L); /* Low Prio. Queue */ - - lp->txrcommit++; - sti(); - - /* Update statistics */ - lp->stats.tx_packets++; + unsigned long flags; + int i, ok_flag; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ringptr; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4210, TRACE ); + printk("hp100: %s: start_xmit_bm\n",dev->name); +#endif + + if ( skb==NULL ) + { +#ifndef LINUX_2_1 + dev_tint( dev ); +#endif + return 0; + } + + if ( skb->len <= 0 ) return 0; + + /* Get Tx ring tail pointer */ + if( lp->txrtail->next==lp->txrhead ) + { + /* No memory. */ +#ifdef HP100_DEBUG + printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name); +#endif + /* not waited long enough since last tx? */ + if ( jiffies - dev->trans_start < HZ ) return -EAGAIN; + + if ( lp->lan_type < 0 ) /* no LAN type detected yet? */ + { + hp100_stop_interface( dev ); + if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 ) + { + printk( "hp100: %s: no connection found - check wire\n", dev->name ); + hp100_start_interface( dev ); /* 10Mb/s RX pkts maybe handled */ + return -EIO; + } + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ + hp100_start_interface( dev ); + } + + if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 ) + /* we have a 100Mb/s adapter but it isn't connected to hub */ + { + printk( "hp100: %s: login to 100Mb/s hub retry\n", dev->name ); + hp100_stop_interface( dev ); + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + hp100_ints_off(); + i = hp100_sense_lan( dev ); + hp100_ints_on(); + if ( i == HP100_LAN_ERR ) + printk( "hp100: %s: link down detected\n", dev->name ); + else + if ( lp->lan_type != i ) /* cable change! */ + { + /* it's very hard - all network setting must be changed!!! */ + printk( "hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); + lp->lan_type = i; + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + printk( "hp100: %s: interface reset\n", dev->name ); + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + } + + dev->trans_start = jiffies; + return -EAGAIN; + } + + /* + * we have to turn int's off before modifying this, otherwise + * a tx_pdl_cleanup could occur at the same time + */ + save_flags( flags ); + cli(); + ringptr=lp->txrtail; + lp->txrtail=ringptr->next; + + /* Check whether packet has minimal packet size */ + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; + + ringptr->skb=skb; + ringptr->pdl[0]=((1<<16) | i); /* PDH: 1 Fragment & length */ + ringptr->pdl[1]=(u32)virt_to_bus(skb->data); /* 1st Frag: Adr. of data */ + if(lp->chip==HP100_CHIPID_SHASTA) + { + /* TODO:Could someone who has the EISA card please check if this works? */ + ringptr->pdl[2]=i; + } + else /* Lassen */ + { + /* In the PDL, don't use the padded size but the real packet size: */ + ringptr->pdl[2]=skb->len; /* 1st Frag: Length of frag */ + } + + /* Hand this PDL to the card. */ + hp100_outl( ringptr->pdl_paddr, TX_PDA_L ); /* Low Prio. Queue */ + + lp->txrcommit++; + restore_flags( flags ); + + /* Update statistics */ + lp->stats.tx_packets++; #ifdef LINUX_2_1 - lp->stats.tx_bytes += skb->len; + lp->stats.tx_bytes += skb->len; #endif - dev->trans_start = jiffies; - - return 0; + dev->trans_start = jiffies; + + return 0; } - + /* clean_txring checks if packets have been sent by the card by reading * the TX_PDL register from the performance page and comparing it to the * number of commited packets. It then frees the skb's of the packets that @@ -1447,168 +1673,209 @@ * * Needs the PERFORMANCE page selected. */ -static void hp100_clean_txring(struct device *dev) +static void hp100_clean_txring( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int ioaddr = dev->base_addr; - int donecount; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + int donecount; #ifdef HP100_DEBUG_B - hp100_outw(0x4211, TRACE); - printk("hp100: clean txring\n"); + hp100_outw( 0x4211, TRACE ); + printk("hp100: %s: clean txring\n", dev->name); #endif - /* How many PDLs have been transmitted? */ - donecount = (lp->txrcommit) - hp100_inb(TX_PDL); + /* How many PDLs have been transmitted? */ + donecount=(lp->txrcommit)-hp100_inb(TX_PDL); #ifdef HP100_DEBUG - if (donecount > MAX_TX_PDL) - printk("hp100: Warning: More PDLs transmitted than commited to card???\n"); + if(donecount>MAX_TX_PDL) + printk("hp100: %s: Warning: More PDLs transmitted than commited to card???\n",dev->name); #endif - for (; 0 != donecount; donecount--) { + for( ; 0!=donecount; donecount-- ) + { #ifdef HP100_DEBUG_BM - printk("hp100: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", - (u_int) lp->txrhead->skb->data, - lp->txrcommit, - hp100_inb(TX_PDL), - donecount); -#endif - dev_kfree_skb(lp->txrhead->skb, FREE_WRITE); - lp->txrhead->skb = (void *) NULL; - lp->txrhead = lp->txrhead->next; - lp->txrcommit--; - } + printk("hp100: %s: Free skb: data @0x%.8x txrcommit=0x%x TXPDL=0x%x, done=0x%x\n", + dev->name, + (u_int) lp->txrhead->skb->data, + lp->txrcommit, + hp100_inb(TX_PDL), + donecount); +#endif +#ifdef LINUX_2_1 + dev_kfree_skb( lp->txrhead->skb ); +#else + dev_kfree_skb( lp->txrhead->skb, FREE_WRITE ); +#endif + lp->txrhead->skb=(void *)NULL; + lp->txrhead=lp->txrhead->next; + lp->txrcommit--; + } } - + /* tx function for slave modes */ -static int hp100_start_xmit(struct sk_buff *skb, struct device *dev) +static int hp100_start_xmit( struct sk_buff *skb, struct device *dev ) { - int i, ok_flag; - int ioaddr = dev->base_addr; - u_short val; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4212, TRACE); - printk("hp100: start_xmit\n"); -#endif + int i, ok_flag; + int ioaddr = dev->base_addr; + u_short val; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4212, TRACE ); + printk("hp100: %s: start_xmit\n", dev->name); +#endif + + if ( skb==NULL ) + { +#ifndef LINUX_2_1 + dev_tint( dev ); +#endif + return 0; + } + + if ( skb->len <= 0 ) return 0; + + if ( lp->lan_type < 0 ) /* no LAN type detected yet? */ + { + hp100_stop_interface( dev ); + if ( ( lp->lan_type = hp100_sense_lan( dev ) ) < 0 ) + { + printk( "hp100: %s: no connection found - check wire\n", dev->name ); + hp100_start_interface( dev ); /* 10Mb/s RX packets maybe handled */ + return -EIO; + } + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); /* relogin */ + hp100_start_interface( dev ); + } + + /* If there is not enough free memory on the card... */ + i=hp100_inl(TX_MEM_FREE)&0x7fffffff; + if ( !(((i/2)-539)>(skb->len+16) && (hp100_inb(TX_PKT_CNT)<255)) ) + { +#ifdef HP100_DEBUG + printk( "hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i ); +#endif + /* not waited long enough since last failed tx try? */ + if ( jiffies - dev->trans_start < HZ ) + { +#ifdef HP100_DEBUG + printk("hp100: %s: trans_start timing problem\n", dev->name); +#endif + return -EAGAIN; + } + if ( lp->lan_type == HP100_LAN_100 && lp->hub_status < 0 ) + /* we have a 100Mb/s adapter but it isn't connected to hub */ + { + printk( "hp100: %s: login to 100Mb/s hub retry\n", dev->name ); + hp100_stop_interface( dev ); + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + hp100_ints_off(); + i = hp100_sense_lan( dev ); + hp100_ints_on(); + if ( i == HP100_LAN_ERR ) + printk( "hp100: %s: link down detected\n", dev->name ); + else + if ( lp->lan_type != i ) /* cable change! */ + { + /* it's very hard - all network setting must be changed!!! */ + printk( "hp100: %s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name ); + lp->lan_type = i; + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + } + else + { + printk( "hp100: %s: interface reset\n", dev->name ); + hp100_stop_interface( dev ); + if ( lp->lan_type == HP100_LAN_100 ) + lp->hub_status = hp100_login_to_vg_hub( dev, FALSE ); + hp100_start_interface( dev ); + udelay(1000); + } + } + dev->trans_start = jiffies; + return -EAGAIN; + } - if (lp->lan_type < 0) { /* no LAN type detected yet? */ - hp100_stop_interface(dev); - if ((lp->lan_type = hp100_sense_lan(dev)) < 0) { - printk("%s: no connection found - check wire\n", dev->name); - hp100_start_interface(dev); /* 10Mb/s RX packets maybe handled */ - return -EIO; - } - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); /* relogin */ - hp100_start_interface(dev); - } - /* If there is not enough free memory on the card... */ - i = hp100_inl(TX_MEM_FREE) & 0x7fffffff; - if (!(((i / 2) - 539) > (skb->len + 16) && (hp100_inb(TX_PKT_CNT) < 255))) { -#ifdef HP100_DEBUG - printk("hp100_start_xmit: tx free mem = 0x%x\n", i); -#endif - /* not waited long enough since last failed tx try? */ - if (jiffies - dev->trans_start < HZ / 2) { -#ifdef HP100_DEBUG - printk("hp100: trans_start timing problem\n"); -#endif - return -EAGAIN; - } - if (lp->lan_type == HP100_LAN_100 && lp->hub_status < 0) - /* we have a 100Mb/s adapter but it isn't connected to hub */ - { - printk("%s: login to 100Mb/s hub retry\n", dev->name); - hp100_stop_interface(dev); - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); - hp100_start_interface(dev); - } else { - hp100_ints_off(); - i = hp100_sense_lan(dev); - hp100_page(PERFORMANCE); - hp100_ints_on(); - if (i == HP100_LAN_ERR) - printk("%s: link down detected\n", dev->name); - else if (lp->lan_type != i) { /* cable change! */ - /* it's very hard - all network setting must be changed!!! */ - printk("%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev->name); - lp->lan_type = i; - hp100_stop_interface(dev); - if (lp->lan_type == HP100_LAN_100) - lp->hub_status = hp100_login_to_vg_hub(dev, FALSE); - hp100_start_interface(dev); - } else { - printk("%s: interface reset\n", dev->name); - hp100_stop_interface(dev); - hp100_start_interface(dev); - udelay(1000); - } - } - dev->trans_start = jiffies; - return -EAGAIN; - } - for (i = 0; i < 6000 && (hp100_inb(OPTION_MSW) & HP100_TX_CMD); i++) { + for ( i=0; i<6000 && ( hp100_inb( OPTION_MSW ) & HP100_TX_CMD ); i++ ) + { #ifdef HP100_DEBUG_TX - printk("hp100_start_xmit: busy\n"); + printk( "hp100: %s: start_xmit: busy\n", dev->name ); #endif - } - - hp100_ints_off(); - val = hp100_inw(IRQ_STATUS); - /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set - * when the current packet being transmitted on the wire is completed. */ - hp100_outw(HP100_TX_COMPLETE, IRQ_STATUS); + } + + hp100_ints_off(); + val = hp100_inw( IRQ_STATUS ); + /* Ack / clear the interrupt TX_COMPLETE interrupt - this interrupt is set + * when the current packet being transmitted on the wire is completed. */ + hp100_outw( HP100_TX_COMPLETE, IRQ_STATUS ); #ifdef HP100_DEBUG_TX - printk("hp100_start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n", val, hp100_inw(IRQ_MASK), (int) skb->len); + printk("hp100: %s: start_xmit: irq_status=0x%.4x, irqmask=0x%.4x, len=%d\n",dev->name,val,hp100_inw(IRQ_MASK),(int)skb->len ); #endif - ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; - i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; - - hp100_outw(i, DATA32); /* tell card the total packet length */ - hp100_outw(i, FRAGMENT_LEN); /* and first/only fragment length */ + ok_flag = skb->len >= HP100_MIN_PACKET_SIZE; + i = ok_flag ? skb->len : HP100_MIN_PACKET_SIZE; - if (lp->mode == 2) { /* memory mapped */ - if (lp->mem_ptr_virt) { /* high pci memory was remapped */ - /* Note: The J2585B needs alignment to 32bits here! */ - memcpy(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3); - if (!ok_flag) - memset(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len); - } else { - memcpy_toio(lp->mem_ptr_phys, skb->data, skb->len); - if (!ok_flag) - memset_io(lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len); - } - } else { /* programmed i/o */ - outsl(ioaddr + HP100_REG_DATA32, skb->data, (skb->len + 3) >> 2); - if (!ok_flag) - for (i = (skb->len + 3) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4) - hp100_outl(0, DATA32); - } - - hp100_outb(HP100_TX_CMD | HP100_SET_LB, OPTION_MSW); /* send packet */ - - lp->stats.tx_packets++; + hp100_outw( i, DATA32 ); /* tell card the total packet length */ + hp100_outw( i, FRAGMENT_LEN ); /* and first/only fragment length */ + + if ( lp->mode==2 ) /* memory mapped */ + { + if ( lp->mem_ptr_virt ) /* high pci memory was remapped */ + { + /* Note: The J2585B needs alignment to 32bits here! */ + memcpy( lp->mem_ptr_virt, skb->data, ( skb->len + 3 ) & ~3 ); + if ( !ok_flag ) + memset( lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len ); + } + else + { + /* Note: The J2585B needs alignment to 32bits here! */ + memcpy_toio( lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3 ); + if ( !ok_flag ) + memset_io( lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len ); + } + } + else /* programmed i/o */ + { + outsl( ioaddr + HP100_REG_DATA32, skb->data, ( skb->len + 3 ) >> 2 ); + if ( !ok_flag ) + for ( i = ( skb->len + 3 ) & ~3; i < HP100_MIN_PACKET_SIZE; i += 4 ) + hp100_outl( 0, DATA32 ); + } + + hp100_outb( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */ + + lp->stats.tx_packets++; #ifdef LINUX_2_1 - lp->stats.tx_bytes += skb->len; + lp->stats.tx_bytes += skb->len; #endif - dev->trans_start = jiffies; - hp100_ints_on(); - - dev_kfree_skb(skb, FREE_WRITE); - + dev->trans_start=jiffies; + hp100_ints_on(); + +#ifdef LINUX_2_1 + dev_kfree_skb( skb ); +#else + dev_kfree_skb( skb, FREE_WRITE ); +#endif + #ifdef HP100_DEBUG_TX - printk("hp100_start_xmit: end\n"); + printk( "hp100: %s: start_xmit: end\n", dev->name ); #endif - - return 0; + + return 0; } - + /* * Receive Function (Non-Busmaster mode) * Called when an "Receive Packet" interrupt occurs, i.e. the receive @@ -1618,981 +1885,1163 @@ * and netif_rx. */ -static void hp100_rx(struct device *dev) +static void hp100_rx( struct device *dev ) { - int packets, pkt_len; - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - u_int header; - struct sk_buff *skb; + int packets, pkt_len; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + u_int header; + struct sk_buff *skb; #ifdef DEBUG_B - hp100_outw(0x4213, TRACE); - printk("hp100: rx\n"); + hp100_outw( 0x4213, TRACE ); + printk("hp100: %s: rx\n", dev->name); #endif - /* First get indication of received lan packet */ - /* RX_PKT_CND indicates the number of packets which have been fully */ - /* received onto the card but have not been fully transfered of the card */ - packets = hp100_inb(RX_PKT_CNT); + /* First get indication of received lan packet */ + /* RX_PKT_CND indicates the number of packets which have been fully */ + /* received onto the card but have not been fully transfered of the card */ + packets = hp100_inb( RX_PKT_CNT ); #ifdef HP100_DEBUG_RX - if (packets > 1) - printk("hp100_rx: waiting packets = %d\n", packets); + if ( packets > 1 ) + printk( "hp100: %s: rx: waiting packets = %d\n", dev->name,packets ); #endif - while (packets-- > 0) { - /* If ADV_NXT_PKT is still set, we have to wait until the card has */ - /* really advanced to the next packet. */ - for (pkt_len = 0; pkt_len < 6000 && (hp100_inb(OPTION_MSW) & HP100_ADV_NXT_PKT); - pkt_len++) { + while ( packets-- > 0 ) + { + /* If ADV_NXT_PKT is still set, we have to wait until the card has */ + /* really advanced to the next packet. */ + for (pkt_len=0; pkt_len<6000 &&(hp100_inb(OPTION_MSW)&HP100_ADV_NXT_PKT); + pkt_len++ ) + { #ifdef HP100_DEBUG_RX - printk("hp100_rx: busy, remaining packets = %d\n", packets); -#endif - } - - /* First we get the header, which contains information about the */ - /* actual length of the received packet. */ - if (lp->mode == 2) { /* memory mapped mode */ - if (lp->mem_ptr_virt) /* if memory was remapped */ - header = *(__u32 *) lp->mem_ptr_virt; - else - header = readl(lp->mem_ptr_phys); - } else /* programmed i/o */ - header = hp100_inl(DATA32); - - pkt_len = header & HP100_PKT_LEN_MASK; + printk( "hp100: %s: rx: busy, remaining packets = %d\n", dev->name, packets ); +#endif + } + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + if( lp->mode==2 ) /* memory mapped mode */ + { + if ( lp->mem_ptr_virt ) /* if memory was remapped */ + header = *(__u32 *)lp->mem_ptr_virt; + else + header = readl( lp->mem_ptr_phys ); + } + else /* programmed i/o */ + header = hp100_inl( DATA32 ); + + pkt_len = ((header & HP100_PKT_LEN_MASK) + 3) & ~3; #ifdef HP100_DEBUG_RX - printk("hp100_rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", - header & HP100_PKT_LEN_MASK, (header >> 16) & 0xfff8, - (header >> 16) & 7); -#endif - - /* Now we allocate the skb and transfer the data into it. */ - /* NOTE! This (and the skb_put() below) depends on the skb-functions - * allocating more than asked (notably, aligning the request up to - * the next 16-byte length). - */ - skb = dev_alloc_skb(pkt_len); - if (skb == NULL) { /* Not enough memory->drop packet */ -#ifdef HP100_DEBUG - printk("hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len); -#endif - lp->stats.rx_dropped++; - } else { /* skb successfully allocated */ - u_char *ptr; - - skb->dev = dev; - - /* ptr to start of the sk_buff data area */ - ptr = (u_char *) skb_put(skb, pkt_len); - - /* Now transfer the data from the card into that area */ - if (lp->mode == 2) { - if (lp->mem_ptr_virt) - memcpy(ptr, lp->mem_ptr_virt, (pkt_len + 3) & ~3); - /* Note alignment to 32bit transfers */ - else - memcpy_fromio(ptr, lp->mem_ptr_phys, (pkt_len + 3) & ~3); - } else /* io mapped */ - insl(ioaddr + HP100_REG_DATA32, ptr, (pkt_len + 3) >> 2); + printk( "hp100: %s: rx: new packet - length=%d, errors=0x%x, dest=0x%x\n", + dev->name, + header & HP100_PKT_LEN_MASK, (header>>16)&0xfff8, + (header>>16)&7); +#endif + + /* Now we allocate the skb and transfer the data into it. */ + skb = dev_alloc_skb( pkt_len ); + if ( skb == NULL ) /* Not enough memory->drop packet */ + { +#ifdef HP100_DEBUG + printk( "hp100: %s: rx: couldn't allocate a sk_buff of size %d\n", dev->name, pkt_len ); +#endif + lp->stats.rx_dropped++; + } + else /* skb successfully allocated */ + { + u_char *ptr; + + skb->dev = dev; + + /* ptr to start of the sk_buff data area */ + ptr = (u_char *)skb_put( skb, pkt_len ); + + /* Now transfer the data from the card into that area */ + if ( lp->mode==2 ) + { + if ( lp->mem_ptr_virt ) + memcpy( ptr, lp->mem_ptr_virt, pkt_len ); + /* Note alignment to 32bit transfers */ + else + memcpy_fromio( ptr, lp->mem_ptr_phys, pkt_len ); + } + else /* io mapped */ + insl( ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2 ); + + skb->protocol = eth_type_trans( skb, dev ); - skb->protocol = eth_type_trans(skb, dev); - - netif_rx(skb); - lp->stats.rx_packets++; + netif_rx( skb ); + lp->stats.rx_packets++; #ifdef LINUX_2_1 - lp->stats.rx_bytes += skb->len; + lp->stats.rx_bytes += skb->len; #endif - + #ifdef HP100_DEBUG_RX - printk("rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], - ptr[6], ptr[7], ptr[8], ptr[9], ptr[10], ptr[11]); -#endif - } - - /* Indicate the card that we have got the packet */ - hp100_outb(HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW); - - switch (header & 0x00070000) { - case (HP100_MULTI_ADDR_HASH << 16): - case (HP100_MULTI_ADDR_NO_HASH << 16): - lp->stats.multicast++; - break; - } - } /* end of while(there are packets) loop */ + printk( "hp100: %s: rx: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + dev->name, + ptr[ 0 ], ptr[ 1 ], ptr[ 2 ], ptr[ 3 ], ptr[ 4 ], ptr[ 5 ], + ptr[ 6 ], ptr[ 7 ], ptr[ 8 ], ptr[ 9 ], ptr[ 10 ], ptr[ 11 ] ); +#endif + } + + /* Indicate the card that we have got the packet */ + hp100_outb( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW ); + + switch ( header & 0x00070000 ) { + case (HP100_MULTI_ADDR_HASH<<16): + case (HP100_MULTI_ADDR_NO_HASH<<16): + lp->stats.multicast++; break; + } + } /* end of while(there are packets) loop */ #ifdef HP100_DEBUG_RX - printk("hp100_rx: end\n"); + printk( "hp100_rx: %s: end\n", dev->name ); #endif } - + /* * Receive Function for Busmaster Mode */ -static void hp100_rx_bm(struct device *dev) +static void hp100_rx_bm( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - hp100_ring_t *ptr; - u_int header; - int pkt_len; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4214, TRACE); - printk("hp100: rx_bm\n"); + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + hp100_ring_t *ptr; + u_int header; + int pkt_len; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4214, TRACE ); + printk("hp100: %s: rx_bm\n", dev->name); #endif #ifdef HP100_DEBUG - if (0 == lp->rxrcommit) { - printk("hp100: rx_bm called although no PDLs were committed to adapter?\n"); - return; - } else - /* RX_PKT_CNT states how many PDLs are currently formatted and available to - * the cards BM engine */ - if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) { - printk("hp100: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", hp100_inw(RX_PKT_CNT) & 0x00ff, lp->rxrcommit); - return; - } -#endif - - while ((lp->rxrcommit > hp100_inb(RX_PDL))) { - /* - * The packet was received into the pdl pointed to by lp->rxrhead ( - * the oldest pdl in the ring - */ - - /* First we get the header, which contains information about the */ - /* actual length of the received packet. */ - - ptr = lp->rxrhead; - - header = *(ptr->pdl - 1); - pkt_len = (header & HP100_PKT_LEN_MASK); + if(0==lp->rxrcommit) + { + printk("hp100: %s: rx_bm called although no PDLs were committed to adapter?\n", dev->name); + return; + } + else + + /* RX_PKT_CNT states how many PDLs are currently formatted and available to + * the cards BM engine */ + if( (hp100_inw(RX_PKT_CNT)&0x00ff) >= lp->rxrcommit) + { + printk("hp100: %s: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n", dev->name, hp100_inw(RX_PKT_CNT)&0x00ff, lp->rxrcommit); + return; + } +#endif + + while( (lp->rxrcommit > hp100_inb(RX_PDL)) ) + { + /* + * The packet was received into the pdl pointed to by lp->rxrhead ( + * the oldest pdl in the ring + */ + + /* First we get the header, which contains information about the */ + /* actual length of the received packet. */ + + ptr=lp->rxrhead; + + header = *(ptr->pdl-1); + pkt_len = (header & HP100_PKT_LEN_MASK); #ifdef HP100_DEBUG_BM - printk("hp100: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", - (u_int) (ptr->pdl - 1), (u_int) header, - pkt_len, - (header >> 16) & 0xfff8, - (header >> 16) & 7); - printk("hp100: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", - hp100_inb(RX_PDL), - hp100_inb(TX_PDL), - hp100_inb(RX_PKT_CNT), - (u_int) * (ptr->pdl), - (u_int) * (ptr->pdl + 3), - (u_int) * (ptr->pdl + 4)); -#endif - - if ((pkt_len >= MIN_ETHER_SIZE) && - (pkt_len <= MAX_ETHER_SIZE)) { - if (ptr->skb == NULL) { - printk("hp100: rx_bm: skb null\n"); - /* can happen if we only allocated room for the pdh due to memory shortage. */ - lp->stats.rx_dropped++; - } else { - skb_trim(ptr->skb, pkt_len); /* Shorten it */ - ptr->skb->protocol = eth_type_trans(ptr->skb, dev); - - netif_rx(ptr->skb); /* Up and away... */ + printk( "hp100: %s: rx_bm: header@0x%x=0x%x length=%d, errors=0x%x, dest=0x%x\n", + dev->name, + (u_int) (ptr->pdl-1),(u_int) header, + pkt_len, + (header>>16)&0xfff8, + (header>>16)&7); + printk( "hp100: %s: RX_PDL_COUNT:0x%x TX_PDL_COUNT:0x%x, RX_PKT_CNT=0x%x PDH=0x%x, Data@0x%x len=0x%x\n", + dev->name, + hp100_inb( RX_PDL ), + hp100_inb( TX_PDL ), + hp100_inb( RX_PKT_CNT ), + (u_int) *(ptr->pdl), + (u_int) *(ptr->pdl+3), + (u_int) *(ptr->pdl+4)); +#endif + + if( (pkt_len>=MIN_ETHER_SIZE) && + (pkt_len<=MAX_ETHER_SIZE) ) + { + if(ptr->skb==NULL) + { + printk("hp100: %s: rx_bm: skb null\n", dev->name); + /* can happen if we only allocated room for the pdh due to memory shortage. */ + lp->stats.rx_dropped++; + } + else + { + skb_trim( ptr->skb, pkt_len ); /* Shorten it */ + ptr->skb->protocol = eth_type_trans( ptr->skb, dev ); + + netif_rx( ptr->skb ); /* Up and away... */ - lp->stats.rx_packets++; + lp->stats.rx_packets++; #ifdef LINUX_2_1 - lp->stats.rx_bytes += ptr->skb->len; + lp->stats.rx_bytes += ptr->skb->len; #endif - } - - switch (header & 0x00070000) { - case (HP100_MULTI_ADDR_HASH << 16): - case (HP100_MULTI_ADDR_NO_HASH << 16): - lp->stats.multicast++; - break; - } - } else { -#ifdef HP100_DEBUG - printk("hp100: rx_bm: Received bad packet (length=%d)\n", pkt_len); -#endif - if (ptr->skb != NULL) - dev_kfree_skb(ptr->skb, FREE_READ); - lp->stats.rx_errors++; - } - - lp->rxrhead = lp->rxrhead->next; - - /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ - if (0 == hp100_build_rx_pdl(lp->rxrtail, dev)) { - /* No space for skb, header can still be received. */ -#ifdef HP100_DEBUG - printk("hp100: rx_bm: No space for new PDL.\n"); -#endif - return; - } else { /* successfully allocated new PDL - put it in ringlist at tail. */ - hp100_outl((u32) lp->rxrtail->pdl_paddr, RX_PDA); - lp->rxrtail = lp->rxrtail->next; - } + } + switch ( header & 0x00070000 ) { + case (HP100_MULTI_ADDR_HASH<<16): + case (HP100_MULTI_ADDR_NO_HASH<<16): + lp->stats.multicast++; break; + } + } + else + { +#ifdef HP100_DEBUG + printk("hp100: %s: rx_bm: Received bad packet (length=%d)\n",dev->name,pkt_len); +#endif + if(ptr->skb!=NULL) +#ifdef LINUX_2_1 + dev_kfree_skb( ptr->skb ); +#else + dev_kfree_skb( ptr->skb, FREE_READ ); +#endif + lp->stats.rx_errors++; + } + + lp->rxrhead=lp->rxrhead->next; + + /* Allocate a new rx PDL (so lp->rxrcommit stays the same) */ + if (0 == hp100_build_rx_pdl( lp->rxrtail, dev )) + { + /* No space for skb, header can still be received. */ +#ifdef HP100_DEBUG + printk("hp100: %s: rx_bm: No space for new PDL.\n", dev->name); +#endif + return; + } + else + { /* successfully allocated new PDL - put it in ringlist at tail. */ + hp100_outl((u32)lp->rxrtail->pdl_paddr, RX_PDA); + lp->rxrtail=lp->rxrtail->next; } + + } } - + /* * statistics */ -static hp100_stats_t *hp100_get_stats(struct device *dev) +static hp100_stats_t *hp100_get_stats( struct device *dev ) { - int ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; #ifdef HP100_DEBUG_B - hp100_outw(0x4215, TRACE); + hp100_outw( 0x4215, TRACE ); #endif - hp100_ints_off(); - hp100_update_stats(dev); - hp100_ints_on(); - return &((struct hp100_private *) dev->priv)->stats; + hp100_ints_off(); + hp100_update_stats( dev ); + hp100_ints_on(); + return &((struct hp100_private *)dev->priv)->stats; } -static void hp100_update_stats(struct device *dev) +static void hp100_update_stats( struct device *dev ) { - int ioaddr = dev->base_addr; - u_short val; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + u_short val; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4216, TRACE); - printk("hp100: update-stats\n"); + hp100_outw( 0x4216, TRACE ); + printk("hp100: %s: update-stats\n", dev->name); #endif - /* Note: Statistics counters clear when read. */ - hp100_page(MAC_CTRL); - val = hp100_inw(DROPPED) & 0x0fff; - lp->stats.rx_errors += val; - lp->stats.rx_over_errors += val; - val = hp100_inb(CRC); - lp->stats.rx_errors += val; - lp->stats.rx_crc_errors += val; - val = hp100_inb(ABORT); - lp->stats.tx_errors += val; - lp->stats.tx_aborted_errors += val; - hp100_page(PERFORMANCE); + /* Note: Statistics counters clear when read. */ + hp100_page( MAC_CTRL ); + val = hp100_inw( DROPPED ) & 0x0fff; + lp->stats.rx_errors += val; + lp->stats.rx_over_errors += val; + val = hp100_inb( CRC ); + lp->stats.rx_errors += val; + lp->stats.rx_crc_errors += val; + val = hp100_inb( ABORT ); + lp->stats.tx_errors += val; + lp->stats.tx_aborted_errors += val; + hp100_page( PERFORMANCE ); } -static void hp100_clear_stats(int ioaddr) +static void hp100_misc_interrupt( struct device *dev ) { + struct hp100_private *lp = (struct hp100_private *)dev->priv; + #ifdef HP100_DEBUG_B - hp100_outw(0x4217, TRACE); - printk("hp100: clear_stats\n"); + hp100_outw( 0x4216, TRACE ); + printk("hp100: %s: misc_interrupt\n", dev->name); #endif - cli(); - hp100_page(MAC_CTRL); /* get all statistics bytes */ - hp100_inw(DROPPED); - hp100_inb(CRC); - hp100_inb(ABORT); - hp100_page(PERFORMANCE); - sti(); + /* Note: Statistics counters clear when read. */ + lp->stats.rx_errors++; + lp->stats.tx_errors++; +} + +static void hp100_clear_stats( int ioaddr ) +{ + unsigned long flags; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4217, TRACE ); + printk("hp100: %s: clear_stats\n", dev->name); +#endif + + save_flags( flags ); + cli(); + hp100_page( MAC_CTRL ); /* get all statistics bytes */ + hp100_inw( DROPPED ); + hp100_inb( CRC ); + hp100_inb( ABORT ); + hp100_page( PERFORMANCE ); + restore_flags( flags ); } - + /* * multicast setup */ /* * Set or clear the multicast filter for this adapter. - * TODO: Currently when in multicast mode, card accepts all multicast packets - * for all MC addresses. Should better use the list on the card. */ - -static void hp100_set_multicast_list(struct device *dev) + +static void hp100_set_multicast_list( struct device *dev ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4218, TRACE); - printk("hp100: set_mc_list\n"); -#endif - - cli(); - hp100_ints_off(); - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); /* stop rx/tx */ - - if (dev->flags & IFF_PROMISC) { - lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ - lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ - } else if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) { - lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ - lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ - } else { - lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ - lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ - } - - if (((hp100_inb(MAC_CFG_1) & 0x0f) != lp->mac1_mode) || - (hp100_inb(MAC_CFG_2) != lp->mac2_mode)) { - hp100_outb(lp->mac2_mode, MAC_CFG_2); - hp100_andb(HP100_MAC1MODEMASK, MAC_CFG_1); /* clear mac1 mode bits */ - hp100_orb(lp->mac1_mode, MAC_CFG_1); /* and set the new mode */ - - if (lp->lan_type == HP100_LAN_100) { -#ifdef HP100_DEBUG - printk("hp100: 100VG MAC settings have changed - relogin.\n"); + unsigned long flags; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4218, TRACE ); + printk("hp100: %s: set_mc_list\n", dev->name); +#endif + + save_flags( flags ); + cli(); + hp100_ints_off(); + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */ + + if ( dev->flags & IFF_PROMISC ) + { + lp->mac2_mode = HP100_MAC2MODE6; /* promiscuous mode = get all good */ + lp->mac1_mode = HP100_MAC1MODE6; /* packets on the net */ + memset( &lp->hash_bytes, 0xff, 8 ); + } + else if ( dev->mc_count || (dev->flags&IFF_ALLMULTI) ) + { + lp->mac2_mode = HP100_MAC2MODE5; /* multicast mode = get packets for */ + lp->mac1_mode = HP100_MAC1MODE5; /* me, broadcasts and all multicasts */ +#ifdef HP100_MULTICAST_FILTER /* doesn't work!!! */ + if ( dev -> flags & IFF_ALLMULTI ) + { + /* set hash filter to receive all multicast packets */ + memset( &lp->hash_bytes, 0xff, 8 ); + } + else + { + int i, j, idx; + u_char *addrs; + struct dev_mc_list *dmi; + + memset( &lp->hash_bytes, 0x00, 8 ); +#ifdef HP100_DEBUG + printk("hp100: %s: computing hash filter - mc_count = %i\n", dev -> name, dev -> mc_count ); +#endif + for ( i = 0, dmi = dev -> mc_list; i < dev -> mc_count; i++, dmi = dmi -> next ) + { + addrs = dmi -> dmi_addr; + if ( ( *addrs & 0x01 ) == 0x01 ) /* multicast address? */ + { +#ifdef HP100_DEBUG + printk("hp100: %s: multicast = %02x:%02x:%02x:%02x:%02x:%02x, ", + dev -> name, + addrs[ 0 ], addrs[ 1 ], addrs[ 2 ], + addrs[ 3 ], addrs[ 4 ], addrs[ 5 ] ); +#endif + for ( j = idx = 0; j < 6; j++ ) + { + idx ^= *addrs++ & 0x3f; + printk( ":%02x:", idx ); + } +#ifdef HP100_DEBUG + printk("idx = %i\n", idx ); +#endif + lp->hash_bytes[ idx >> 3 ] |= ( 1 << ( idx & 7 ) ); + } + } + } +#else + memset( &lp->hash_bytes, 0xff, 8 ); #endif - lp->hub_status = hp100_login_to_vg_hub(dev, TRUE); /* force a relogin to the hub */ - } - } - hp100_page(MAC_CTRL); - hp100_orb(HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ - HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1); /* enable tx */ - - hp100_page(PERFORMANCE); - hp100_ints_on(); - sti(); + } + else + { + lp->mac2_mode = HP100_MAC2MODE3; /* normal mode = get packets for me */ + lp->mac1_mode = HP100_MAC1MODE3; /* and broadcasts */ + memset( &lp->hash_bytes, 0x00, 8 ); + } + + if ( ( (hp100_inb(MAC_CFG_1) & 0x0f)!=lp->mac1_mode ) || + ( hp100_inb(MAC_CFG_2)!=lp->mac2_mode ) ) + { + int i; + + hp100_outb( lp->mac2_mode, MAC_CFG_2 ); + hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 ); /* clear mac1 mode bits */ + hp100_orb( lp->mac1_mode, MAC_CFG_1 ); /* and set the new mode */ + + hp100_page( MAC_ADDRESS ); + for ( i = 0; i < 8; i++ ) + hp100_outb( lp->hash_bytes[ i ], HASH_BYTE0 + i ); +#ifdef HP100_DEBUG + printk("hp100: %s: mac1 = 0x%x, mac2 = 0x%x, multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, lp->mac1_mode, lp->mac2_mode, + lp->hash_bytes[ 0 ], lp->hash_bytes[ 1 ], + lp->hash_bytes[ 2 ], lp->hash_bytes[ 3 ], + lp->hash_bytes[ 4 ], lp->hash_bytes[ 5 ], + lp->hash_bytes[ 6 ], lp->hash_bytes[ 7 ] + ); +#endif + + if(lp->lan_type==HP100_LAN_100) + { +#ifdef HP100_DEBUG + printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name); +#endif + lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */ + } + } + else + { + int i; + u_char old_hash_bytes[ 8 ]; + + hp100_page( MAC_ADDRESS ); + for ( i = 0; i < 8; i++ ) + old_hash_bytes[ i ] = hp100_inb( HASH_BYTE0 + i ); + if ( memcmp( old_hash_bytes, &lp->hash_bytes, 8 ) ) + { + for ( i = 0; i < 8; i++ ) + hp100_outb( lp->hash_bytes[ i ], HASH_BYTE0 + i ); +#ifdef HP100_DEBUG + printk("hp100: %s: multicast hash = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + lp->hash_bytes[ 0 ], lp->hash_bytes[ 1 ], + lp->hash_bytes[ 2 ], lp->hash_bytes[ 3 ], + lp->hash_bytes[ 4 ], lp->hash_bytes[ 5 ], + lp->hash_bytes[ 6 ], lp->hash_bytes[ 7 ] + ); +#endif + + if(lp->lan_type==HP100_LAN_100) + { +#ifdef HP100_DEBUG + printk("hp100: %s: 100VG MAC settings have changed - relogin.\n", dev->name); +#endif + lp->hub_status=hp100_login_to_vg_hub( dev, TRUE ); /* force a relogin to the hub */ + } + } + } + + hp100_page( MAC_CTRL ); + hp100_orb( HP100_RX_EN | HP100_RX_IDLE | /* enable rx */ + HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */ + + hp100_page( PERFORMANCE ); + hp100_ints_on(); + restore_flags( flags ); } - + /* * hardware interrupt handling */ -static void hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void hp100_interrupt( int irq, void *dev_id, struct pt_regs *regs ) { - struct device *dev = dev_id; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + struct device *dev = (struct device *)dev_id; + struct hp100_private *lp = (struct hp100_private *)dev->priv; - int ioaddr; - u_int val; + int ioaddr; + u_int val; - if (dev == NULL) - return; - ioaddr = dev->base_addr; + if ( dev == NULL ) return; + ioaddr = dev->base_addr; - if (dev->interrupt) - printk("%s: re-entering the interrupt handler\n", dev->name); - hp100_ints_off(); - dev->interrupt = 1; /* mark that we are inside the handler */ + if ( dev->interrupt ) + printk( "hp100: %s: re-entering the interrupt handler\n", dev->name ); + hp100_ints_off(); + dev->interrupt = 1; /* mark that we are inside the handler */ #ifdef HP100_DEBUG_B - hp100_outw(0x4219, TRACE); + hp100_outw( 0x4219, TRACE ); #endif - /* hp100_page( PERFORMANCE ); */ - val = hp100_inw(IRQ_STATUS); + /* hp100_page( PERFORMANCE ); */ + val = hp100_inw( IRQ_STATUS ); #ifdef HP100_DEBUG_IRQ - printk("hp100: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n", - lp->mode, - (u_int) val, - hp100_inb(RX_PKT_CNT), - hp100_inb(RX_PDL), - hp100_inb(TX_PKT_CNT), - hp100_inb(TX_PDL) - ); -#endif - - if (val == 0) { /* might be a shared interrupt */ - dev->interrupt = 0; - hp100_ints_on(); - return; - } - /* We're only interested in those interrupts we really enabled. */ - /* val &= hp100_inw( IRQ_MASK ); */ - - /* - * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL - * is considered executed whenever the RX_PDL data structure is no longer - * needed. - */ - if (val & HP100_RX_PDL_FILL_COMPL) { - if (lp->mode == 1) - hp100_rx_bm(dev); - else - printk("hp100: rx_pdl_fill_compl interrupt although not busmaster?\n"); - } - /* - * The RX_PACKET interrupt is set, when the receive packet counter is - * non zero. We use this interrupt for receiving in slave mode. In - * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill - * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then - * we somehow have missed a rx_pdl_fill_compl interrupt. - */ - - if (val & HP100_RX_PACKET) { /* Receive Packet Counter is non zero */ - if (lp->mode != 1) /* non busmaster */ - hp100_rx(dev); - else if (!(val & HP100_RX_PDL_FILL_COMPL)) { - /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */ - hp100_rx_bm(dev); - } - } - /* - * Ack. that we have noticed the interrupt and thereby allow next one. - * Note that this is now done after the slave rx function, since first - * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt - * on the J2573. - */ - hp100_outw(val, IRQ_STATUS); - - /* - * RX_ERROR is set when a packet is dropped due to no memory resources on - * the card or when a RCV_ERR occurs. - * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists - * only in the 802.3 MAC and happens when 16 collisions occur during a TX - */ - if (val & (HP100_TX_ERROR | HP100_RX_ERROR)) { + printk( "hp100: %s: mode=%x,IRQ_STAT=0x%.4x,RXPKTCNT=0x%.2x RXPDL=0x%.2x TXPKTCNT=0x%.2x TXPDL=0x%.2x\n", + dev->name, + lp->mode, + (u_int)val, + hp100_inb( RX_PKT_CNT ), + hp100_inb( RX_PDL ), + hp100_inb( TX_PKT_CNT ), + hp100_inb( TX_PDL ) + ); +#endif + + if(val==0) /* might be a shared interrupt */ + { + dev->interrupt=0; + hp100_ints_on(); + return; + } + /* We're only interested in those interrupts we really enabled. */ + /* val &= hp100_inw( IRQ_MASK ); */ + + /* + * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL + * is considered executed whenever the RX_PDL data structure is no longer + * needed. + */ + if ( val & HP100_RX_PDL_FILL_COMPL ) + { + if(lp->mode==1) + hp100_rx_bm( dev ); + else + { + printk("hp100: %s: rx_pdl_fill_compl interrupt although not busmaster?\n", dev->name); + } + } + + /* + * The RX_PACKET interrupt is set, when the receive packet counter is + * non zero. We use this interrupt for receiving in slave mode. In + * busmaster mode, we use it to make sure we did not miss any rx_pdl_fill + * interrupts. If rx_pdl_fill_compl is not set and rx_packet is set, then + * we somehow have missed a rx_pdl_fill_compl interrupt. + */ + + if ( val & HP100_RX_PACKET ) /* Receive Packet Counter is non zero */ + { + if(lp->mode!=1) /* non busmaster */ + hp100_rx( dev ); + else if ( !(val & HP100_RX_PDL_FILL_COMPL )) + { + /* Shouldnt happen - maybe we missed a RX_PDL_FILL Interrupt? */ + hp100_rx_bm( dev ); + } + } + + /* + * Ack. that we have noticed the interrupt and thereby allow next one. + * Note that this is now done after the slave rx function, since first + * acknowledging and then setting ADV_NXT_PKT caused an extra interrupt + * on the J2573. + */ + hp100_outw( val, IRQ_STATUS ); + + /* + * RX_ERROR is set when a packet is dropped due to no memory resources on + * the card or when a RCV_ERR occurs. + * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists + * only in the 802.3 MAC and happens when 16 collisions occur during a TX + */ + if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) ) + { #ifdef HP100_DEBUG_IRQ - printk("hp100: TX/RX Error IRQ\n"); + printk("hp100: %s: TX/RX Error IRQ\n", dev->name); #endif - hp100_update_stats(dev); - if (lp->mode == 1) { - hp100_rxfill(dev); - hp100_clean_txring(dev); - } - } - /* - * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. - */ - if ((lp->mode == 1) && (val & (HP100_RX_PDA_ZERO))) - hp100_rxfill(dev); - - /* - * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire - * is completed - */ - if ((lp->mode == 1) && (val & (HP100_TX_COMPLETE))) - hp100_clean_txring(dev); - - /* - * MISC_ERROR is set when either the LAN link goes down or a detected - * bus error occurs. - */ - if (val & HP100_MISC_ERROR) { /* New for J2585B */ - printk("hp100: Misc. Error Interrupt - Check cabling.\n"); - if (lp->mode == 1) { - hp100_clean_txring(dev); - hp100_rxfill(dev); - } - } - dev->interrupt = 0; - hp100_ints_on(); + hp100_update_stats( dev ); + if(lp->mode==1) + { + hp100_rxfill( dev ); + hp100_clean_txring( dev ); + } + } + + /* + * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero. + */ + if ( (lp->mode==1)&&(val &(HP100_RX_PDA_ZERO)) ) + hp100_rxfill( dev ); + + /* + * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire + * is completed + */ + if ( (lp->mode==1) && ( val & ( HP100_TX_COMPLETE )) ) + hp100_clean_txring( dev ); + + /* + * MISC_ERROR is set when either the LAN link goes down or a detected + * bus error occurs. + */ + if ( val & HP100_MISC_ERROR ) /* New for J2585B */ + { +#ifdef HP100_DEBUG_IRQ + printk("hp100: %s: Misc. Error Interrupt - Check cabling.\n", dev->name); +#endif + if(lp->mode==1) + { + hp100_clean_txring( dev ); + hp100_rxfill( dev ); + } + hp100_misc_interrupt( dev ); + } + + dev->interrupt = 0; + hp100_ints_on(); } - + /* * some misc functions */ -static void hp100_start_interface(struct device *dev) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4220, TRACE); - printk("hp100: hp100_start_interface %s\n", dev->name); -#endif - - cli(); - - /* Ensure the adapter does not want to request an interrupt when */ - /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack all IRQs */ - hp100_outw(HP100_FAKE_INT | HP100_INT_EN | HP100_RESET_LB, OPTION_LSW); - /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */ - hp100_outw(HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW); - - if (lp->mode == 1) { - /* Make sure BM bit is set... */ - hp100_page(HW_MAP); - hp100_orb(HP100_BM_MASTER, BM); - hp100_rxfill(dev); - } else if (lp->mode == 2) { - /* Enable memory mapping. Note: Don't do this when busmaster. */ - hp100_outw(HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW); - } - hp100_page(PERFORMANCE); - hp100_outw(0xfefe, IRQ_MASK); /* mask off all ints */ - hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */ - - /* enable a few interrupts: */ - if (lp->mode == 1) { /* busmaster mode */ - hp100_outw(HP100_RX_PDL_FILL_COMPL | - HP100_RX_PDA_ZERO | - HP100_RX_ERROR | - /* HP100_RX_PACKET | */ - /* HP100_RX_EARLY_INT | */ HP100_SET_HB | - /* HP100_TX_PDA_ZERO | */ - HP100_TX_COMPLETE | - /* HP100_MISC_ERROR | */ - HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); - } else { - hp100_outw(HP100_RX_PACKET | - HP100_RX_ERROR | HP100_SET_HB | - HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK); - } - - /* Enable MAC Tx and RX, set MAC modes, ... */ - /* Note: This function also turns on the interrupts. */ - hp100_set_multicast_list(dev); -} - - -static void hp100_stop_interface(struct device *dev) +static void hp100_start_interface( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int ioaddr = dev->base_addr; - u_int val; - -#ifdef HP100_DEBUG_B - printk("hp100: hp100_stop_interface %s\n", dev->name); - hp100_outw(0x4221, TRACE); -#endif - - if (lp->mode == 1) - hp100_BM_shutdown(dev); - else { - /* Note: MMAP_DIS will be reenabled by start_interface */ - hp100_outw(HP100_INT_EN | HP100_RESET_LB | - HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW); - val = hp100_inw(OPTION_LSW); - - hp100_page(MAC_CTRL); - hp100_andb(~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1); - - if (!(val & HP100_HW_RST)) - return; /* If reset, imm. return ... */ - /* ... else: busy wait until idle */ - for (val = 0; val < 6000; val++) - if ((hp100_inb(MAC_CFG_1) & (HP100_TX_IDLE | HP100_RX_IDLE)) == - (HP100_TX_IDLE | HP100_RX_IDLE)) { - hp100_page(PERFORMANCE); - return; - } - printk("%s: hp100_stop_interface - timeout\n", dev->name); - hp100_page(PERFORMANCE); - } + unsigned long flags; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4220, TRACE ); + printk("hp100: %s: hp100_start_interface\n",dev->name); +#endif + + save_flags( flags ); + cli(); + + /* Ensure the adapter does not want to request an interrupt when */ + /* enabling the IRQ line to be active on the bus (i.e. not tri-stated) */ + hp100_page( PERFORMANCE ); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack all IRQs */ + hp100_outw( HP100_FAKE_INT|HP100_INT_EN|HP100_RESET_LB, OPTION_LSW); + /* Un Tri-state int. TODO: Check if shared interrupts can be realised? */ + hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW ); + + if(lp->mode==1) + { + /* Make sure BM bit is set... */ + hp100_page(HW_MAP); + hp100_orb( HP100_BM_MASTER, BM ); + hp100_rxfill( dev ); + } + else if(lp->mode==2) + { + /* Enable memory mapping. Note: Don't do this when busmaster. */ + hp100_outw( HP100_MMAP_DIS | HP100_RESET_HB, OPTION_LSW ); + } + + hp100_page(PERFORMANCE); + hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */ + hp100_outw( 0xffff, IRQ_STATUS ); /* ack IRQ */ + + /* enable a few interrupts: */ + if(lp->mode==1) /* busmaster mode */ + { + hp100_outw( HP100_RX_PDL_FILL_COMPL | + HP100_RX_PDA_ZERO | + HP100_RX_ERROR | + /* HP100_RX_PACKET | */ + /* HP100_RX_EARLY_INT | */ HP100_SET_HB | + /* HP100_TX_PDA_ZERO | */ + HP100_TX_COMPLETE | + /* HP100_MISC_ERROR | */ + HP100_TX_ERROR | HP100_SET_LB, IRQ_MASK ); + } + else + { + hp100_outw( HP100_RX_PACKET | + HP100_RX_ERROR | HP100_SET_HB | + HP100_TX_ERROR | HP100_SET_LB , IRQ_MASK ); + } + + /* Enable MAC Tx and RX, set MAC modes, ... */ + hp100_set_multicast_list( dev ); + + restore_flags( flags ); +} + + +static void hp100_stop_interface( struct device *dev ) +{ + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + u_int val; + +#ifdef HP100_DEBUG_B + printk("hp100: %s: hp100_stop_interface\n",dev->name); + hp100_outw( 0x4221, TRACE ); +#endif + + if (lp->mode==1) + hp100_BM_shutdown( dev ); + else + { + /* Note: MMAP_DIS will be reenabled by start_interface */ + hp100_outw( HP100_INT_EN | HP100_RESET_LB | + HP100_TRI_INT | HP100_MMAP_DIS | HP100_SET_HB, OPTION_LSW ); + val = hp100_inw( OPTION_LSW ); + + hp100_page( MAC_CTRL ); + hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); + + if ( !(val & HP100_HW_RST) ) return; /* If reset, imm. return ... */ + /* ... else: busy wait until idle */ + for ( val = 0; val < 6000; val++ ) + if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) == + (HP100_TX_IDLE | HP100_RX_IDLE) ) + { + hp100_page(PERFORMANCE); + return; + } + printk( "hp100: %s: hp100_stop_interface - timeout\n", dev->name ); + hp100_page(PERFORMANCE); + } +} + + +static void hp100_load_eeprom( struct device *dev, u_short probe_ioaddr ) +{ + int i; + int ioaddr = probe_ioaddr > 0 ? probe_ioaddr : dev->base_addr; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4222, TRACE ); +#endif + + hp100_page( EEPROM_CTRL ); + hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL ); + hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL ); + for ( i = 0; i < 10000; i++ ) + if ( !( hp100_inb( OPTION_MSW ) & HP100_EE_LOAD ) ) return; + printk( "hp100: %s: hp100_load_eeprom - timeout\n", dev->name ); } - -static void hp100_load_eeprom(struct device *dev) -{ - int i; - int ioaddr = dev->base_addr; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4222, TRACE); -#endif - - hp100_page(EEPROM_CTRL); - hp100_andw(~HP100_EEPROM_LOAD, EEPROM_CTRL); - hp100_orw(HP100_EEPROM_LOAD, EEPROM_CTRL); - for (i = 0; i < 10000; i++) - if (!(hp100_inb(OPTION_MSW) & HP100_EE_LOAD)) - return; - printk("%s: hp100_load_eeprom - timeout\n", dev->name); -} - /* Sense connection status. * return values: LAN_10 - Connected to 10Mbit/s network * LAN_100 - Connected to 100Mbit/s network * LAN_ERR - not connected or 100Mbit/s Hub down */ -static int hp100_sense_lan(struct device *dev) +static int hp100_sense_lan( struct device *dev ) { - int ioaddr = dev->base_addr; - u_short val_VG, val_10; - struct hp100_private *lp = (struct hp100_private *) dev->priv; + int ioaddr = dev->base_addr; + u_short val_VG, val_10; + struct hp100_private *lp = (struct hp100_private *)dev->priv; #ifdef HP100_DEBUG_B - hp100_outw(0x4223, TRACE); + hp100_outw( 0x4223, TRACE ); #endif - hp100_page(MAC_CTRL); - /* Enable Auto Selection */ - /* hp100_orb( HP100_VG_RESET|HP100_LINK_CMD|HP100_VG_SEL, VG_LAN_CFG_1 ); */ - /* hp100_orb( HP100_DOT3_MAC,10_LAN_CFG_2); */ - /* hp100_orb( HP100_AUTO_MODE,MAC_CFG_3); */ - /* Now we have to wait a while... */ - /* for(i=0; i<5000; i++) */ - /* { */ - val_10 = hp100_inb(10_LAN_CFG_1); - val_VG = hp100_inb(VG_LAN_CFG_1); - /* } */ + hp100_page( MAC_CTRL ); + val_10 = hp100_inb( 10_LAN_CFG_1 ); + val_VG = hp100_inb( VG_LAN_CFG_1 ); + hp100_page( PERFORMANCE ); #ifdef HP100_DEBUG - printk("hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10); + printk( "hp100: %s: sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", dev->name, val_VG, val_10 ); #endif - if (val_10 & HP100_LINK_BEAT_ST) - return HP100_LAN_10; - if ((lp->id->id == 0x02019F022) || - (lp->id->id == 0x01042103c) || - (lp->id->id == 0x01040103c)) { - hp100_page(PERFORMANCE); - return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ - } - /* for ( i = 0; i < 2500; i++ ) */ - /* { */ - val_VG = hp100_inb(VG_LAN_CFG_1); - hp100_page(PERFORMANCE); - if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */ - return HP100_LAN_100; - /* } */ - return HP100_LAN_ERR; + if ( val_10 & HP100_LINK_BEAT_ST ) /* 10Mb connection is active */ + return HP100_LAN_10; + + if ( val_10 & HP100_AUI_ST ) /* have we BNC or AUI onboard? */ + { + val_10 |= HP100_AUI_SEL | HP100_LOW_TH; + hp100_page( MAC_CTRL ); + hp100_outb( val_10, 10_LAN_CFG_1 ); + hp100_page( PERFORMANCE ); + return HP100_LAN_10; + } + + if ( (lp->id->id == 0x02019F022) || + (lp->id->id == 0x01042103c) || + (lp->id->id == 0x01040103c) ) + return HP100_LAN_ERR; /* Those cards don't have a 100 Mbit connector */ + + if ( val_VG & HP100_LINK_CABLE_ST ) /* Can hear the HUBs tone. */ + return HP100_LAN_100; + return HP100_LAN_ERR; } - -static int hp100_down_vg_link(struct device *dev) + +static int hp100_down_vg_link( struct device *dev ) { - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int ioaddr = dev->base_addr; - unsigned long time; - long savelan, newlan; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long time; + long savelan, newlan; #ifdef HP100_DEBUG_B - hp100_outw(0x4224, TRACE); - printk("hp100: down_vg_link\n"); + hp100_outw( 0x4224, TRACE ); + printk("hp100: %s: down_vg_link\n", dev->name); #endif - hp100_page(MAC_CTRL); - time = jiffies + (HZ / 4); - do { - if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) - break; - } while (time > jiffies); + hp100_page( MAC_CTRL ); + time=jiffies+(HZ/4); + do{ + if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break; + } while (time>jiffies); - if (jiffies >= time) /* no signal->no logout */ - return 0; + if ( jiffies >= time ) /* no signal->no logout */ + return 0; - /* Drop the VG Link by clearing the link up cmd and load addr. */ + /* Drop the VG Link by clearing the link up cmd and load addr.*/ - hp100_andb(~(HP100_LOAD_ADDR | HP100_LINK_CMD), VG_LAN_CFG_1); - hp100_orb(HP100_VG_SEL, VG_LAN_CFG_1); + hp100_andb( ~( HP100_LOAD_ADDR| HP100_LINK_CMD), VG_LAN_CFG_1); + hp100_orb( HP100_VG_SEL, VG_LAN_CFG_1); - /* Conditionally stall for >250ms on Link-Up Status (to go down) */ - time = jiffies + (HZ / 2); - do { - if (!(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) - break; - } while (time > jiffies); + /* Conditionally stall for >250ms on Link-Up Status (to go down) */ + time=jiffies+(HZ/2); + do{ + if ( !(hp100_inb( VG_LAN_CFG_1) & HP100_LINK_UP_ST) ) break; + } while(time>jiffies); #ifdef HP100_DEBUG - if (jiffies >= time) - printk("hp100_down_vg_link: Link does not go down?\n"); + if (jiffies>=time) + printk("hp100: %s: down_vg_link: Link does not go down?\n", dev->name); #endif - /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */ - /* logout under traffic (even though all the status bits are cleared), */ - /* do this workaround to get the Rev 1 MAC in its idle state */ - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Reset VG MAC to insure it leaves the logoff state even if */ - /* the Hub is still emitting tones */ - hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1); - udelay(1500); /* wait for >1ms */ - hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */ - udelay(1500); - } - /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */ - /* to get the VG mac to full reset. This is not req.d with later chips */ - /* Note: It will take the between 1 and 2 seconds for the VG mac to be */ - /* selected again! This will be left to the connect hub function to */ - /* perform if desired. */ - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Have to write to 10 and 100VG control registers simultaneously */ - savelan = newlan = hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */ - newlan &= ~(HP100_VG_SEL << 16); - newlan |= (HP100_DOT3_MAC) << 8; - hp100_andb(~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */ - hp100_outl(newlan, 10_LAN_CFG_1); + /* To prevent condition where Rev 1 VG MAC and old hubs do not complete */ + /* logout under traffic (even though all the status bits are cleared), */ + /* do this workaround to get the Rev 1 MAC in its idle state */ + if ( lp->chip==HP100_CHIPID_LASSEN ) + { + /* Reset VG MAC to insure it leaves the logoff state even if */ + /* the Hub is still emitting tones */ + hp100_andb(~HP100_VG_RESET, VG_LAN_CFG_1); + udelay(1500); /* wait for >1ms */ + hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); /* Release Reset */ + udelay(1500); + } - /* Conditionally stall for 5sec on VG selected. */ - time = jiffies + (HZ * 5); - do { - if (!(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) - break; - } while (time > jiffies); + /* New: For lassen, switch to 10 Mbps mac briefly to clear training ACK */ + /* to get the VG mac to full reset. This is not req.d with later chips */ + /* Note: It will take the between 1 and 2 seconds for the VG mac to be */ + /* selected again! This will be left to the connect hub function to */ + /* perform if desired. */ + if (lp->chip==HP100_CHIPID_LASSEN) + { + /* Have to write to 10 and 100VG control registers simultaneously */ + savelan=newlan=hp100_inl(10_LAN_CFG_1); /* read 10+100 LAN_CFG regs */ + newlan &= ~(HP100_VG_SEL<<16); + newlan |= (HP100_DOT3_MAC)<<8; + hp100_andb( ~HP100_AUTO_MODE, MAC_CFG_3); /* Autosel off */ + hp100_outl(newlan, 10_LAN_CFG_1); - hp100_orb(HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ - hp100_outl(savelan, 10_LAN_CFG_1); - } - time = jiffies + (3 * HZ); /* Timeout 3s */ - do { - if ((hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) == 0) - break; - } while (time > jiffies); + /* Conditionally stall for 5sec on VG selected. */ + time=jiffies+(HZ*5); + do{ + if( !(hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST) ) break; + } while(time>jiffies); + + hp100_orb( HP100_AUTO_MODE, MAC_CFG_3); /* Autosel back on */ + hp100_outl(savelan, 10_LAN_CFG_1); + } - if (time <= jiffies) { + time=jiffies+(3*HZ); /* Timeout 3s */ + do { + if ( (hp100_inb( VG_LAN_CFG_1 )&HP100_LINK_CABLE_ST) == 0) break; + } while (time>jiffies); + + if(time<=jiffies) + { #ifdef HP100_DEBUG - printk("hp100_down_vg_link: timeout\n"); + printk( "hp100: %s: down_vg_link: timeout\n", dev->name ); #endif - return -EIO; - } - time = jiffies + (2 * HZ); /* This seems to take a while.... */ - do { - } while (time > jiffies); - - return 0; + return -EIO; + } + + time=jiffies+(2*HZ); /* This seems to take a while.... */ + do {} while (time>jiffies); + + return 0; } - -static int hp100_login_to_vg_hub(struct device *dev, u_short force_relogin) + +static int hp100_login_to_vg_hub( struct device *dev, u_short force_relogin ) { - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - u_short val = 0; - unsigned long time; - int startst; + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + u_short val=0; + unsigned long time; + int startst; #ifdef HP100_DEBUG_B - hp100_outw(0x4225, TRACE); - printk("hp100: login_to_vg_hub\n"); + hp100_outw( 0x4225, TRACE ); + printk("hp100: %s: login_to_vg_hub\n", dev->name); #endif - /* Initiate a login sequence iff VG MAC is enabled and either Load Address - * bit is zero or the force relogin flag is set (e.g. due to MAC address or - * promiscuous mode change) - */ - hp100_page(MAC_CTRL); - startst = hp100_inb(VG_LAN_CFG_1); - if ((force_relogin == TRUE) || (hp100_inb(MAC_CFG_4) & HP100_MAC_SEL_ST)) { + /* Initiate a login sequence iff VG MAC is enabled and either Load Address + * bit is zero or the force relogin flag is set (e.g. due to MAC address or + * promiscuous mode change) + */ + hp100_page( MAC_CTRL ); + startst=hp100_inb( VG_LAN_CFG_1 ); + if((force_relogin==TRUE)||(hp100_inb( MAC_CFG_4 )&HP100_MAC_SEL_ST)) + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: Start training\n"); + printk("hp100: %s: Start training\n", dev->name); #endif - /* Ensure VG Reset bit is 1 (i.e., do not reset) */ - hp100_orb(HP100_VG_RESET, VG_LAN_CFG_1); + /* Ensure VG Reset bit is 1 (i.e., do not reset)*/ + hp100_orb( HP100_VG_RESET , VG_LAN_CFG_1 ); - /* If Lassen AND auto-select-mode AND VG tones were sensed on */ - /* entry then temporarily put them into force 100Mbit mode */ - if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) - hp100_andb(~HP100_DOT3_MAC, 10_LAN_CFG_2); - - /* Drop the VG link by zeroing Link Up Command and Load Address */ - hp100_andb(~(HP100_LINK_CMD /* |HP100_LOAD_ADDR */ ), VG_LAN_CFG_1); + /* If Lassen AND auto-select-mode AND VG tones were sensed on */ + /* entry then temporarily put them into force 100Mbit mode */ + if((lp->chip==HP100_CHIPID_LASSEN)&&( startst & HP100_LINK_CABLE_ST ) ) + hp100_andb( ~HP100_DOT3_MAC, 10_LAN_CFG_2 ); + + /* Drop the VG link by zeroing Link Up Command and Load Address */ + hp100_andb( ~(HP100_LINK_CMD/* |HP100_LOAD_ADDR */), VG_LAN_CFG_1); #ifdef HP100_DEBUG_TRAINING - printk("hp100: Bring down the link\n"); + printk("hp100: %s: Bring down the link\n", dev->name); #endif - /* Wait for link to drop */ - time = jiffies + (HZ / 10); - do { - if (~(hp100_inb(VG_LAN_CFG_1) & HP100_LINK_UP_ST)) - break; - } while (time > jiffies); - - /* Start an addressed training and optionally request promiscuous port */ - if ((dev->flags) & IFF_PROMISC) { - hp100_orb(HP100_PROM_MODE, VG_LAN_CFG_2); - if (lp->chip == HP100_CHIPID_LASSEN) - hp100_orw(HP100_MACRQ_PROMSC, TRAIN_REQUEST); - } else { - hp100_andb(~HP100_PROM_MODE, VG_LAN_CFG_2); - /* For ETR parts we need to reset the prom. bit in the training - * register, otherwise promiscious mode won't be disabled. - */ - if (lp->chip == HP100_CHIPID_LASSEN) { - hp100_andw(~HP100_MACRQ_PROMSC, TRAIN_REQUEST); - } - } - - /* With ETR parts, frame format request bits can be set. */ - if (lp->chip == HP100_CHIPID_LASSEN) - hp100_orb(HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST); - - hp100_orb(HP100_LINK_CMD | HP100_LOAD_ADDR | HP100_VG_RESET, VG_LAN_CFG_1); - - /* Note: Next wait could be omitted for Hood and earlier chips under */ - /* certain circumstances */ - /* TODO: check if hood/earlier and skip wait. */ - - /* Wait for either short timeout for VG tones or long for login */ - /* Wait for the card hardware to signalise link cable status ok... */ - hp100_page(MAC_CTRL); - time = jiffies + (1 * HZ); /* 1 sec timeout for cable st */ - do { - if (hp100_inb(VG_LAN_CFG_1) & HP100_LINK_CABLE_ST) - break; - } while (jiffies < time); - - if (jiffies >= time) { + /* Wait for link to drop */ + time = jiffies + (HZ/10); + do { + if (~(hp100_inb( VG_LAN_CFG_1 )& HP100_LINK_UP_ST) ) break; + } while (time>jiffies); + + /* Start an addressed training and optionally request promiscuous port */ + if ( (dev->flags) & IFF_PROMISC ) + { + hp100_orb( HP100_PROM_MODE, VG_LAN_CFG_2); + if(lp->chip==HP100_CHIPID_LASSEN) + hp100_orw( HP100_MACRQ_PROMSC, TRAIN_REQUEST ); + } + else + { + hp100_andb( ~HP100_PROM_MODE, VG_LAN_CFG_2); + /* For ETR parts we need to reset the prom. bit in the training + * register, otherwise promiscious mode won't be disabled. + */ + if(lp->chip==HP100_CHIPID_LASSEN) + { + hp100_andw( ~HP100_MACRQ_PROMSC, TRAIN_REQUEST ); + } + } + + /* With ETR parts, frame format request bits can be set. */ + if(lp->chip==HP100_CHIPID_LASSEN) + hp100_orb( HP100_MACRQ_FRAMEFMT_EITHER, TRAIN_REQUEST); + + hp100_orb( HP100_LINK_CMD|HP100_LOAD_ADDR|HP100_VG_RESET, VG_LAN_CFG_1); + + /* Note: Next wait could be omitted for Hood and earlier chips under */ + /* certain circumstances */ + /* TODO: check if hood/earlier and skip wait. */ + + /* Wait for either short timeout for VG tones or long for login */ + /* Wait for the card hardware to signalise link cable status ok... */ + hp100_page( MAC_CTRL ); + time = jiffies + ( 1*HZ ); /* 1 sec timeout for cable st */ + do { + if ( hp100_inb( VG_LAN_CFG_1 ) & HP100_LINK_CABLE_ST ) break; + } while ( jiffies < time ); + + if ( jiffies >= time ) + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: Link cable status not ok? Training aborted.\n"); -#endif - } else { + printk( "hp100: %s: Link cable status not ok? Training aborted.\n", dev->name ); +#endif + } + else + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: HUB tones detected. Trying to train.\n"); + printk( "hp100: %s: HUB tones detected. Trying to train.\n", dev->name); #endif - time = jiffies + (2 * HZ); /* again a timeout */ - do { - val = hp100_inb(VG_LAN_CFG_1); - if ((val & (HP100_LINK_UP_ST))) { + time = jiffies + ( 2*HZ ); /* again a timeout */ + do { + val = hp100_inb( VG_LAN_CFG_1 ); + if ( (val & ( HP100_LINK_UP_ST )) ) + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: Passed training.\n"); + printk( "hp100: %s: Passed training.\n", dev->name); #endif - break; - } - } while (time > jiffies); - } - - /* If LINK_UP_ST is set, then we are logged into the hub. */ - if ((jiffies <= time) && (val & HP100_LINK_UP_ST)) { + break; + } + } while ( time > jiffies ); + } + + /* If LINK_UP_ST is set, then we are logged into the hub. */ + if ( (jiffies<=time) && (val & HP100_LINK_UP_ST) ) + { #ifdef HP100_DEBUG_TRAINING - printk("hp100: Successfully logged into the HUB.\n"); - if (lp->chip == HP100_CHIPID_LASSEN) { - val = hp100_inw(TRAIN_ALLOW); - printk("hp100: Card supports 100VG MAC Version \"%s\" ", - (hp100_inw(TRAIN_REQUEST) & HP100_CARD_MACVER) ? "802.12" : "Pre"); - printk("Driver will use MAC Version \"%s\"\n", - (val & HP100_HUB_MACVER) ? "802.12" : "Pre"); - printk("hp100: Frame format is %s.\n", (val & HP100_MALLOW_FRAMEFMT) ? "802.5" : "802.3"); - } -#endif - } else { - /* If LINK_UP_ST is not set, login was not successful */ - printk("hp100/%s: Problem logging into the HUB.\n", dev->name); - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Check allowed Register to find out why there is a problem. */ - val = hp100_inw(TRAIN_ALLOW); /* wont work on non-ETR card */ + printk( "hp100: %s: Successfully logged into the HUB.\n", dev->name); + if(lp->chip==HP100_CHIPID_LASSEN) + { + val = hp100_inw(TRAIN_ALLOW); + printk( "hp100: %s: Card supports 100VG MAC Version \"%s\" ", + dev->name,(hp100_inw(TRAIN_REQUEST)&HP100_CARD_MACVER) ? "802.12" : "Pre"); + printk( "Driver will use MAC Version \"%s\"\n", + ( val & HP100_HUB_MACVER) ? "802.12" : "Pre" ); + printk( "hp100: %s: Frame format is %s.\n",dev->name,(val&HP100_MALLOW_FRAMEFMT)?"802.5":"802.3"); + } +#endif + } + else + { + /* If LINK_UP_ST is not set, login was not successful */ + printk("hp100: %s: Problem logging into the HUB.\n",dev->name); + if(lp->chip==HP100_CHIPID_LASSEN) + { + /* Check allowed Register to find out why there is a problem. */ + val = hp100_inw( TRAIN_ALLOW ); /* wont work on non-ETR card */ #ifdef HP100_DEBUG_TRAINING - printk("hp100: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", hp100_inw(TRAIN_REQUEST), val); + printk("hp100: %s: MAC Configuration requested: 0x%04x, HUB allowed: 0x%04x\n", dev->name, hp100_inw(TRAIN_REQUEST), val); #endif - if (val & HP100_MALLOW_ACCDENIED) - printk("hp100: HUB access denied.\n"); - if (val & HP100_MALLOW_CONFIGURE) - printk("hp100: MAC Configuration is incompatible with the Network.\n"); - if (val & HP100_MALLOW_DUPADDR) - printk("hp100: Duplicate MAC Address on the Network.\n"); - } - } - - /* If we have put the chip into forced 100 Mbit mode earlier, go back */ - /* to auto-select mode */ - - if ((lp->chip == HP100_CHIPID_LASSEN) && (startst & HP100_LINK_CABLE_ST)) { - hp100_page(MAC_CTRL); - hp100_orb(HP100_DOT3_MAC, 10_LAN_CFG_2); - } - val = hp100_inb(VG_LAN_CFG_1); - - /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */ - hp100_page(PERFORMANCE); - hp100_outw(HP100_MISC_ERROR, IRQ_STATUS); - - if (val & HP100_LINK_UP_ST) - return (0); /* login was ok */ - else { - printk("hp100: Training failed.\n"); - hp100_down_vg_link(dev); - return -EIO; - } + if ( val & HP100_MALLOW_ACCDENIED ) + printk("hp100: %s: HUB access denied.\n", dev->name); + if ( val & HP100_MALLOW_CONFIGURE ) + printk("hp100: %s: MAC Configuration is incompatible with the Network.\n", dev->name); + if ( val & HP100_MALLOW_DUPADDR ) + printk("hp100: %s: Duplicate MAC Address on the Network.\n", dev->name); + } + } + + /* If we have put the chip into forced 100 Mbit mode earlier, go back */ + /* to auto-select mode */ + + if( (lp->chip==HP100_CHIPID_LASSEN)&&(startst & HP100_LINK_CABLE_ST) ) + { + hp100_page( MAC_CTRL ); + hp100_orb( HP100_DOT3_MAC, 10_LAN_CFG_2 ); + } + + val=hp100_inb(VG_LAN_CFG_1); + + /* Clear the MISC_ERROR Interrupt, which might be generated when doing the relogin */ + hp100_page(PERFORMANCE); + hp100_outw( HP100_MISC_ERROR, IRQ_STATUS); + + if (val&HP100_LINK_UP_ST) + return(0); /* login was ok */ + else + { + printk("hp100: %s: Training failed.\n", dev->name); + hp100_down_vg_link( dev ); + return -EIO; + } + } + /* no forced relogin & already link there->no training. */ + return -EIO; +} + + +static void hp100_cascade_reset( struct device *dev, u_short enable ) +{ + int ioaddr = dev->base_addr; + struct hp100_private *lp = (struct hp100_private *)dev->priv; + int i; + +#ifdef HP100_DEBUG_B + hp100_outw( 0x4226, TRACE ); + printk("hp100: %s: cascade_reset\n", dev->name); +#endif + + if (enable==TRUE) + { + hp100_outw( HP100_HW_RST | HP100_RESET_LB, OPTION_LSW ); + if(lp->chip==HP100_CHIPID_LASSEN) + { + /* Lassen requires a PCI transmit fifo reset */ + hp100_page( HW_MAP ); + hp100_andb( ~HP100_PCI_RESET, PCICTRL2 ); + hp100_orb( HP100_PCI_RESET, PCICTRL2 ); + /* Wait for min. 300 ns */ + /* we cant use jiffies here, because it may be */ + /* that we have disabled the timer... */ + for (i=0; i<0xffff; i++); + hp100_andb( ~HP100_PCI_RESET, PCICTRL2 ); + hp100_page( PERFORMANCE ); + } + } + else + { /* bring out of reset */ + hp100_outw(HP100_HW_RST|HP100_SET_LB, OPTION_LSW); + for (i=0; i<0xffff; i++ ); + hp100_page(PERFORMANCE); + } +} + +#ifdef HP100_DEBUG +void hp100_RegisterDump( struct device *dev ) +{ + int ioaddr=dev->base_addr; + int Page; + int Register; + + /* Dump common registers */ + printk("hp100: %s: Cascade Register Dump\n", dev->name); + printk("hardware id #1: 0x%.2x\n",hp100_inb(HW_ID)); + printk("hardware id #2/paging: 0x%.2x\n",hp100_inb(PAGING)); + printk("option #1: 0x%.4x\n",hp100_inw(OPTION_LSW)); + printk("option #2: 0x%.4x\n",hp100_inw(OPTION_MSW)); + + /* Dump paged registers */ + for (Page = 0; Page < 8; Page++) + { + /* Dump registers */ + printk("page: 0x%.2x\n",Page); + outw( Page, ioaddr+0x02); + for (Register = 0x8; Register < 0x22; Register += 2) + { + /* Display Register contents except data port */ + if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) + { + printk("0x%.2x = 0x%.4x\n",Register,inw(ioaddr+Register)); + } } - /* no forced relogin & already link there->no training. */ - return -EIO; + } + hp100_page(PERFORMANCE); } - - -static void hp100_cascade_reset(struct device *dev, u_short enable) -{ - int ioaddr = dev->base_addr; - struct hp100_private *lp = (struct hp100_private *) dev->priv; - int i; - -#ifdef HP100_DEBUG_B - hp100_outw(0x4226, TRACE); - printk("hp100: cascade_reset\n"); #endif - if (enable == TRUE) { - hp100_outw(HP100_HW_RST | HP100_RESET_LB, OPTION_LSW); - if (lp->chip == HP100_CHIPID_LASSEN) { - /* Lassen requires a PCI transmit fifo reset */ - hp100_page(HW_MAP); - hp100_andb(~HP100_PCI_RESET, PCICTRL2); - hp100_orb(HP100_PCI_RESET, PCICTRL2); - /* Wait for min. 300 ns */ - /* we cant use jiffies here, because it may be */ - /* that we have disabled the timer... */ - for (i = 0; i < 0xffff; i++); - hp100_andb(~HP100_PCI_RESET, PCICTRL2); - hp100_page(PERFORMANCE); - } - } else { /* bring out of reset */ - hp100_outw(HP100_HW_RST | HP100_SET_LB, OPTION_LSW); - for (i = 0; i < 0xffff; i++); - hp100_page(PERFORMANCE); - } -} -#ifdef HP100_DEBUG -void hp100_RegisterDump(struct device *dev) -{ - int ioaddr = dev->base_addr; - int Page; - int Register; - - /* Dump common registers */ - printk("hp100: Cascade Register Dump\n"); - printk("hardware id #1: 0x%.2x\n", hp100_inb(HW_ID)); - printk("hardware id #2/paging: 0x%.2x\n", hp100_inb(PAGING)); - printk("option #1: 0x%.4x\n", hp100_inw(OPTION_LSW)); - printk("option #2: 0x%.4x\n", hp100_inw(OPTION_MSW)); - - /* Dump paged registers */ - for (Page = 0; Page < 8; Page++) { - /* Dump registers */ - printk("page: 0x%.2x\n", Page); - outw(Page, ioaddr + 0x02); - for (Register = 0x8; Register < 0x22; Register += 2) { - /* Display Register contents except data port */ - if (((Register != 0x10) && (Register != 0x12)) || (Page > 0)) { - printk("0x%.2x = 0x%.4x\n", Register, inw(ioaddr + Register)); - } - } - } - hp100_page(PERFORMANCE); -} -#endif - - /* * module section */ - + #ifdef MODULE /* Parameters set by insmod */ -int hp100_port[5] = -{0, -1, -1, -1, -1}; +int hp100_port[5] = { 0, -1, -1, -1, -1 }; #ifdef LINUX_2_1 MODULE_PARM(hp100_port, "1-5i"); #endif #ifdef LINUX_2_1 -char hp100_name[5][IFNAMSIZ] = -{"", "", "", "", ""}; +char hp100_name[5][IFNAMSIZ] = { "", "", "", "", "" }; MODULE_PARM(hp100_name, "1-5c" __MODULE_STRING(IFNAMSIZ)); #else -static char devname[5][IFNAMSIZ] = -{"", "", "", "", ""}; -static char *hp100_name[5] = -{devname[0], devname[1], - devname[2], devname[3], - devname[4]}; +static char devname[5][IFNAMSIZ] = { "", "", "", "", "" }; +static char *hp100_name[5] = { devname[0], devname[1], + devname[2], devname[3], + devname[4] }; #endif /* List of devices */ -static struct device *hp100_devlist[5] = -{NULL, NULL, NULL, NULL, NULL}; +static struct device *hp100_devlist[5] = { NULL, NULL, NULL, NULL, NULL }; /* * Note: if you have more than five 100vg cards in your pc, feel free to @@ -2606,61 +3055,64 @@ * option hp100 hp100_port=0x280 hp100_name=eth239 */ -int init_module(void) +int init_module( void ) { - int i; - int ret = 0; + int i, cards; - if (hp100_port == 0 && !EISA_bus && !pcibios_present()) - printk("HP100: You should not use auto-probing with insmod!\n"); + if (hp100_port == 0 && !EISA_bus && !pcibios_present()) + printk("hp100: You should not use auto-probing with insmod!\n"); - /* Loop on all possible base addresses */ - i = -1; - while ((hp100_port[++i] != -1) && (i < 5)) { - /* Create device and set basics args */ - hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL); - memset(hp100_devlist[i], 0x00, sizeof(struct device)); - hp100_devlist[i]->name = hp100_name[i]; - hp100_devlist[i]->base_addr = hp100_port[i]; - hp100_devlist[i]->init = &hp100_probe; - - /* Try to create the device */ - if (register_netdev(hp100_devlist[i]) != 0) { - /* DeAllocate everything */ - /* Note: if dev->priv is mallocated, there is no way to fail */ - kfree_s(hp100_devlist[i], sizeof(struct device)); - hp100_devlist[i] = (struct device *) NULL; - ret = -EIO; - } - } /* Loop over all devices */ - - return ret; + /* Loop on all possible base addresses */ + i = -1; cards = 0; + while((hp100_port[++i] != -1) && (i < 5)) + { + /* Create device and set basics args */ + hp100_devlist[i] = kmalloc(sizeof(struct device), GFP_KERNEL); + memset(hp100_devlist[i], 0x00, sizeof(struct device)); + hp100_devlist[i]->name = hp100_name[i]; + hp100_devlist[i]->base_addr = hp100_port[i]; + hp100_devlist[i]->init = &hp100_probe; + + /* Try to create the device */ + if(register_netdev(hp100_devlist[i]) != 0) + { + /* DeAllocate everything */ + /* Note: if dev->priv is mallocated, there is no way to fail */ + kfree_s(hp100_devlist[i], sizeof(struct device)); + hp100_devlist[i] = (struct device *) NULL; + } + else + cards++; + } /* Loop over all devices */ + + return cards > 0 ? 0 : -ENODEV; +} + +void cleanup_module( void ) +{ + int i; + + /* TODO: Check if all skb's are released/freed. */ + for(i = 0; i < 5; i++) + if(hp100_devlist[i] != (struct device *) NULL) + { + unregister_netdev( hp100_devlist[i] ); + release_region( hp100_devlist[i]->base_addr, HP100_REGION_SIZE ); + if( ((struct hp100_private *)hp100_devlist[i]->priv)->mode==1 ) /* busmaster */ + kfree_s( ((struct hp100_private *)hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE+0x0f); + if ( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ) + iounmap( ((struct hp100_private *)hp100_devlist[i]->priv) -> mem_ptr_virt ); + kfree_s( hp100_devlist[i]->priv, sizeof( struct hp100_private ) ); + hp100_devlist[i]->priv = NULL; + kfree_s(hp100_devlist[i], sizeof(struct device)); + hp100_devlist[i] = (struct device *) NULL; + } } -void cleanup_module(void) -{ - int i; +#endif /* MODULE */ - /* TODO: Check if all skb's are released/freed. */ - for (i = 0; i < 5; i++) - if (hp100_devlist[i] != (struct device *) NULL) { - unregister_netdev(hp100_devlist[i]); - release_region(hp100_devlist[i]->base_addr, HP100_REGION_SIZE); - if (((struct hp100_private *) hp100_devlist[i]->priv)->mode == 1) /* busmaster */ - kfree_s(((struct hp100_private *) hp100_devlist[i]->priv)->page_vaddr, MAX_RINGSIZE + 0x0f); - if (((struct hp100_private *) hp100_devlist[i]->priv)->mem_ptr_virt) - iounmap(((struct hp100_private *) hp100_devlist[i]->priv)->mem_ptr_virt); - kfree_s(hp100_devlist[i]->priv, sizeof(struct hp100_private)); - hp100_devlist[i]->priv = NULL; - kfree_s(hp100_devlist[i], sizeof(struct device)); - hp100_devlist[i] = (struct device *) NULL; - } -} -#endif /* MODULE */ - - /* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c" diff -ur --new-file old/linux/drivers/net/hp100.h new/linux/drivers/net/hp100.h --- old/linux/drivers/net/hp100.h Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/hp100.h Wed Mar 18 06:21:43 1998 @@ -1,7 +1,7 @@ /* * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux. * - * $Id: hp100.h,v 1.4 1997/05/26 21:09:19 davem Exp $ + * $Id: hp100.h,v 1.51 1997/04/08 14:26:42 floeff Exp floeff $ * * Authors: Jaroslav Kysela, * Siegfried Loeffler diff -ur --new-file old/linux/drivers/net/hydra.c new/linux/drivers/net/hydra.c --- old/linux/drivers/net/hydra.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/hydra.c Tue Feb 10 21:56:44 1998 @@ -500,7 +500,7 @@ /* clear the unused space */ for(; len1hydra_base + (priv->tx_page_start<<8) + len1) = 0; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); priv->stats.tx_packets++; diff -ur --new-file old/linux/drivers/net/ibmtr.c new/linux/drivers/net/ibmtr.c --- old/linux/drivers/net/ibmtr.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/ibmtr.c Tue Feb 10 21:56:44 1998 @@ -790,7 +790,7 @@ DPRINTK("error on xmit_dir_frame request: %02X\n", xmit_ret_code); if (ti->current_skb) { - dev_kfree_skb(ti->current_skb, FREE_WRITE); + dev_kfree_skb(ti->current_skb); ti->current_skb=NULL; } dev->tbusy=0; @@ -807,7 +807,7 @@ DPRINTK("error on xmit_ui_frame request: %02X\n", xmit_ret_code); if (ti->current_skb) { - dev_kfree_skb(ti->current_skb, FREE_WRITE); + dev_kfree_skb(ti->current_skb); ti->current_skb=NULL; } dev->tbusy=0; @@ -1305,7 +1305,7 @@ writeb(RESP_IN_ASB, ti->mmio + ACA_OFFSET + ACA_SET + ISRA_ODD); dev->tbusy=0; - dev_kfree_skb(ti->current_skb,FREE_WRITE); + dev_kfree_skb(ti->current_skb); ti->current_skb=NULL; mark_bh(NET_BH); if (ti->readlog_pending) ibmtr_readlog(dev); diff -ur --new-file old/linux/drivers/net/ipddp.c new/linux/drivers/net/ipddp.c --- old/linux/drivers/net/ipddp.c Tue Jan 13 00:28:18 1998 +++ new/linux/drivers/net/ipddp.c Thu Mar 12 19:54:12 1998 @@ -83,9 +83,6 @@ /* Index to functions, as function prototypes. */ static int ipddp_xmit(struct sk_buff *skb, struct device *dev); static struct net_device_stats *ipddp_get_stats(struct device *dev); -static int ipddp_rebuild_header(struct sk_buff *skb); -static int ipddp_hard_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); static int ipddp_create(struct ipddp_route *new_rt); static int ipddp_delete(struct ipddp_route *rt); static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); @@ -119,10 +116,10 @@ /* Let the user now what mode we are in */ if(ipddp_mode == IPDDP_ENCAP) - printk("%s: Appletalk-IP Encapsulation mode by Bradford W. Johnson \n", + printk("%s: Appletalk-IP Encap. mode by Bradford W. Johnson \n", dev->name); if(ipddp_mode == IPDDP_DECAP) - printk("%s: Appletalk-IP Decapsulation mode by Jay Schulist \n", + printk("%s: Appletalk-IP Decap. mode by Jay Schulist \n", dev->name); /* Fill in the device structure with ethernet-generic values. */ @@ -140,8 +137,6 @@ dev->stop = ipddp_close; dev->get_stats = ipddp_get_stats; dev->do_ioctl = ipddp_ioctl; - dev->hard_header = ipddp_hard_header; /* see ip_output.c */ - dev->rebuild_header = ipddp_rebuild_header; dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ dev->mtu = 585; @@ -158,24 +153,6 @@ } /* - * Transmit LLAP/ELAP frame using aarp_send_ddp. - */ -static int ipddp_xmit(struct sk_buff *skb, struct device *dev) -{ - /* Retrieve the saved address hint */ - struct at_addr *at = (struct at_addr *)skb->data; - skb_pull(skb,4); - - ((struct net_device_stats *) dev->priv)->tx_packets++; - ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; - - if(aarp_send_ddp(skb->dev, skb, at, NULL) < 0) - dev_kfree_skb(skb,FREE_WRITE); - - return 0; -} - -/* * Get the current statistics. This may be called with the card open or closed. */ static struct net_device_stats *ipddp_get_stats(struct device *dev) @@ -184,19 +161,15 @@ } /* - * Now the packet really wants to go out. On entry skb->data points to the - * ddpehdr we reserved earlier. skb->h.raw will be the higher level header. + * Transmit LLAP/ELAP frame using aarp_send_ddp. */ -static int ipddp_rebuild_header(struct sk_buff *skb) +static int ipddp_xmit(struct sk_buff *skb, struct device *dev) { u32 paddr = ((struct rtable*)skb->dst)->rt_gateway; struct ddpehdr *ddp; - struct at_addr at; struct ipddp_route *rt; struct at_addr *our_addr; - /* Wow! I'll eat my hat if this routine is really called. --ANK */ - /* * Find appropriate route to use, based only on IP number. */ @@ -205,25 +178,21 @@ if(rt->ip == paddr) break; } - if(rt == NULL) - { - printk("%s: unreachable dst %s\n", cardname, in_ntoa(paddr)); - return -ENETUNREACH; - } + return 0; our_addr = atalk_find_dev_addr(rt->dev); if(ipddp_mode == IPDDP_DECAP) /* * Pull off the excess room that should not be there. - * This is the case for Localtalk, this may not hold - * true for Ethertalk, etc. + * This is due to a hard-header problem. This is the + * quick fix for now though, till it breaks. */ - skb_pull(skb, 31-(sizeof(struct ddpehdr)+1)); + skb_pull(skb, 35-(sizeof(struct ddpehdr)+1)); /* Create the Extended DDP header */ - ddp = (struct ddpehdr *) (skb->data+4); + ddp = (struct ddpehdr *)skb->data; ddp->deh_len = skb->len; ddp->deh_hops = 1; ddp->deh_pad = 0; @@ -231,7 +200,7 @@ /* * For Localtalk we need aarp_send_ddp to strip the - * Ext DDP header and place a Shrt DDP header on it. + * long DDP header and place a shot DDP header on it. */ if(rt->dev->type == ARPHRD_LOCALTLK) { @@ -248,25 +217,16 @@ ddp->deh_dport = 72; ddp->deh_sport = 72; - *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ - *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */ + *((__u8 *)(ddp+1)) = 22; /* ddp type = IP */ + *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */ - /* Hide it at the start of the buffer, we pull it out in ipddp_xmit */ - at = rt->at; - memcpy(skb->data,(void *)&at,sizeof(at)); - - skb->dev = rt->dev; /* set skb->dev to appropriate device */ - skb->arp = 1; /* so the actual device doesn't try to arp it... */ skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ - return 0; -} + ((struct net_device_stats *) dev->priv)->tx_packets++; + ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; -static int ipddp_hard_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - /* Push down the header space and the type byte */ - skb_push(skb, sizeof(struct ddpehdr)+1+4); + if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) + dev_kfree_skb(skb); return 0; } diff -ur --new-file old/linux/drivers/net/ipddp.h new/linux/drivers/net/ipddp.h --- old/linux/drivers/net/ipddp.h Mon Dec 22 02:41:24 1997 +++ new/linux/drivers/net/ipddp.h Thu Mar 12 19:54:12 1998 @@ -10,7 +10,6 @@ #define SIOCADDIPDDPRT (SIOCDEVPRIVATE) #define SIOCDELIPDDPRT (SIOCDEVPRIVATE+1) #define SIOCFINDIPDDPRT (SIOCDEVPRIVATE+2) -#define SIOCPRINTIPDDPRT (SIOCDEVPRIVATE+3) struct ipddp_route { diff -ur --new-file old/linux/drivers/net/lance.c new/linux/drivers/net/lance.c --- old/linux/drivers/net/lance.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/lance.c Tue Feb 10 21:56:44 1998 @@ -611,7 +611,7 @@ can watch the LEDs even if the board isn't opened. */ outw(0x0002, ioaddr+LANCE_ADDR); /* set autoselect and clean xmausel */ - outw(inw(ioaddr+LANCE_BUS_IF) & 0xfffe | 0x0002, ioaddr+LANCE_BUS_IF); + outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF); } if (lance_debug > 0 && did_version++ == 0) @@ -667,7 +667,7 @@ /* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */ outw(0x0002, ioaddr+LANCE_ADDR); /* set autoselect and clean xmausel */ - outw(inw(ioaddr+LANCE_BUS_IF) & 0xfffe | 0x0002, ioaddr+LANCE_BUS_IF); + outw((inw(ioaddr+LANCE_BUS_IF) & 0xfffe) | 0x0002, ioaddr+LANCE_BUS_IF); } if (lance_debug > 1) @@ -730,7 +730,7 @@ for (i = 0; i < TX_RING_SIZE; i++) { if (lp->tx_skbuff[i]) { - dev_kfree_skb(lp->tx_skbuff[i],FREE_WRITE); + dev_kfree_skb(lp->tx_skbuff[i]); lp->tx_skbuff[i] = NULL; } } @@ -870,7 +870,7 @@ memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len); lp->tx_ring[entry].base = ((u32)virt_to_bus((lp->tx_bounce_buffs + entry)) & 0xffffff) | 0x83000000; - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); } else { lp->tx_skbuff[entry] = skb; lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000; @@ -969,7 +969,7 @@ /* We must free the original skb if it's not a data-only copy in the bounce buffer. */ if (lp->tx_skbuff[entry]) { - dev_kfree_skb(lp->tx_skbuff[entry],FREE_WRITE); + dev_kfree_skb(lp->tx_skbuff[entry]); lp->tx_skbuff[entry] = 0; } dirty_tx++; diff -ur --new-file old/linux/drivers/net/lapbether.c new/linux/drivers/net/lapbether.c --- old/linux/drivers/net/lapbether.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/lapbether.c Sat Feb 21 03:28:22 1998 @@ -18,7 +18,6 @@ * LAPBETH 001 Jonathan Naylor Cloned from bpqether.c */ -#include #include #include #include @@ -165,7 +164,7 @@ dev = lapbeth_get_x25_dev(dev); if (dev == NULL || dev->start == 0) { - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return 0; } @@ -179,7 +178,7 @@ skb_trim(skb, len); /* Set the length of the data */ if ((err = lapb_data_received(lapbeth, skb)) != LAPB_OK) { - kfree_skb(skb, FREE_READ); + kfree_skb(skb); printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err); } @@ -218,7 +217,7 @@ */ if (!dev->start) { lapbeth_check_devices(dev); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return -ENODEV; } @@ -228,15 +227,15 @@ case 0x01: if ((err = lapb_connect_request(lapbeth)) != LAPB_OK) printk(KERN_ERR "lapbeth: lapb_connect_request error - %d\n", err); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return 0; case 0x02: if ((err = lapb_disconnect_request(lapbeth)) != LAPB_OK) printk(KERN_ERR "lapbeth: lapb_disconnect_request err - %d\n", err); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return 0; default: - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return 0; } @@ -244,7 +243,7 @@ if ((err = lapb_data_request(lapbeth, skb)) != LAPB_OK) { printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return -ENOMEM; } diff -ur --new-file old/linux/drivers/net/loopback.c new/linux/drivers/net/loopback.c --- old/linux/drivers/net/loopback.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/loopback.c Tue Feb 10 21:56:44 1998 @@ -79,10 +79,10 @@ struct sk_buff *skb2=skb; skb=skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */ if(skb==NULL) { - kfree_skb(skb2, FREE_WRITE); + kfree_skb(skb2); return 0; } - kfree_skb(skb2, FREE_WRITE); + kfree_skb(skb2); } else skb_orphan(skb); diff -ur --new-file old/linux/drivers/net/ltpc.c new/linux/drivers/net/ltpc.c --- old/linux/drivers/net/ltpc.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/ltpc.c Sat Feb 21 03:28:22 1998 @@ -180,7 +180,6 @@ #define DEBUG_UPPER 2 #define DEBUG_LOWER 4 -#include /* for CONFIG_MAX_16M */ #ifdef MODULE #include @@ -951,7 +950,7 @@ stats->tx_packets++; stats->tx_bytes+=skb->len; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } diff -ur --new-file old/linux/drivers/net/mace.c new/linux/drivers/net/mace.c --- old/linux/drivers/net/mace.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/mace.c Tue Feb 10 21:56:45 1998 @@ -333,12 +333,12 @@ /* free some skb's */ for (i = 0; i < N_RX_RING; ++i) { if (mp->rx_bufs[i] != 0) { - dev_kfree_skb(mp->rx_bufs[i], FREE_READ); + dev_kfree_skb(mp->rx_bufs[i]); mp->rx_bufs[i] = 0; } } for (i = mp->tx_empty; i != mp->tx_fill; ) { - dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE); + dev_kfree_skb(mp->tx_bufs[i]); if (++i >= N_TX_RING) i = 0; } @@ -601,7 +601,7 @@ ++mp->stats.tx_aborted_errors; } else ++mp->stats.tx_packets; - dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE); + dev_kfree_skb(mp->tx_bufs[i]); --mp->tx_active; if (++i >= N_TX_RING) i = 0; @@ -680,7 +680,7 @@ if (mp->tx_bad_runt) { mp->tx_bad_runt = 0; } else if (i != mp->tx_fill) { - dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE); + dev_kfree_skb(mp->tx_bufs[i]); if (++i >= N_TX_RING) i = 0; mp->tx_empty = i; 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 Tue Jan 13 00:28:18 1998 +++ new/linux/drivers/net/myri_sbus.c Tue Feb 10 21:56:45 1998 @@ -244,7 +244,7 @@ rq->tail = rq->head = 0; for(i = 0; i < (RX_RING_SIZE+1); i++) { if(mp->rx_skbs[i] != NULL) { - dev_kfree_skb(mp->rx_skbs[i], FREE_READ); + dev_kfree_skb(mp->rx_skbs[i]); mp->rx_skbs[i] = NULL; } } @@ -252,7 +252,7 @@ mp->tx_old = sq->tail = sq->head = 0; for(i = 0; i < TX_RING_SIZE; i++) { if(mp->tx_skbs[i] != NULL) { - dev_kfree_skb(mp->tx_skbs[i], FREE_WRITE); + dev_kfree_skb(mp->tx_skbs[i]); mp->tx_skbs[i] = NULL; } } @@ -337,7 +337,7 @@ struct sk_buff *skb = mp->tx_skbs[entry]; DTX(("SKB[%d] ", entry)); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; mp->enet_stats.tx_packets++; diff -ur --new-file old/linux/drivers/net/ne.c new/linux/drivers/net/ne.c --- old/linux/drivers/net/ne.c Tue Dec 9 18:49:58 1997 +++ new/linux/drivers/net/ne.c Thu Feb 19 23:58:40 1998 @@ -72,14 +72,14 @@ #ifdef CONFIG_PCI /* Ack! People are making PCI ne2000 clones! Oh the horror, the horror... */ -static struct { unsigned short vendor, dev_id;} +static struct { unsigned short vendor, dev_id; char *name; } pci_clone_list[] __initdata = { - {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029}, - {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940}, - {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000}, - {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2}, - {PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC}, - {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C926}, + {PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8029, "Realtek 8029" }, + {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_89C940, "Winbond 89C940" }, + {PCI_VENDOR_ID_COMPEX, PCI_DEVICE_ID_COMPEX_RL2000, "Compex ReadyLink 2000" }, + {PCI_VENDOR_ID_KTI, PCI_DEVICE_ID_KTI_ET32P2, "KTI ET32P2" }, + {PCI_VENDOR_ID_NETVIN, PCI_DEVICE_ID_NETVIN_NV5000SC, "NetVin NV5000" }, + {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C926, "VIA 82C926 Amazon" }, {0,} }; #endif @@ -228,9 +228,8 @@ break; /* Beauty -- got a valid card. */ } if (pci_irq_line == 0) continue; /* Try next PCI ID */ - printk("ne.c: PCI BIOS reports %s %s at i/o %#x, irq %d.\n", - pci_strvendor(pci_clone_list[i].vendor), - pci_strdev(pci_clone_list[i].vendor, pci_clone_list[i].dev_id), + printk("ne.c: PCI BIOS reports %s at i/o %#x, irq %d.\n", + pci_clone_list[i].name, pci_ioaddr, pci_irq_line); if (ne_probe1(dev, pci_ioaddr) != 0) { /* Shouldn't happen. */ printk(KERN_ERR "ne.c: Probe of PCI card at %#x failed.\n", pci_ioaddr); @@ -783,11 +782,11 @@ for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { struct device *dev = &dev_ne[this_dev]; if (dev->priv != NULL) { + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; free_irq(dev->irq, dev); release_region(dev->base_addr, NE_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/ni5010.c new/linux/drivers/net/ni5010.c --- old/linux/drivers/net/ni5010.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/ni5010.c Tue Feb 10 21:56:45 1998 @@ -460,7 +460,7 @@ hardware_send_packet(dev, (unsigned char *)skb->data, length); dev->trans_start = jiffies; } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } diff -ur --new-file old/linux/drivers/net/ni52.c new/linux/drivers/net/ni52.c --- old/linux/drivers/net/ni52.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/ni52.c Thu Feb 19 23:58:40 1998 @@ -989,7 +989,7 @@ } #endif -#ifdef 0 +#if 0 if(!at_least_one) { int i; @@ -1203,7 +1203,7 @@ ni_attn586(); dev->trans_start = jiffies; if(!i) - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); WAIT_4_SCB_CMD(); if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */ break; @@ -1223,7 +1223,7 @@ p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); dev->trans_start = jiffies; p->nop_point = next_nop; - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); # endif #else p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len; @@ -1248,7 +1248,7 @@ p->lock = 0; restore_flags(flags); } - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); #endif } return 0; @@ -1338,9 +1338,9 @@ void cleanup_module(void) { release_region(dev_ni52.base_addr, NI52_TOTAL_SIZE); + unregister_netdev(&dev_ni52); kfree(dev_ni52.priv); dev_ni52.priv = NULL; - unregister_netdev(&dev_ni52); } #endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/ni65.c new/linux/drivers/net/ni65.c --- old/linux/drivers/net/ni65.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/ni65.c Thu Feb 19 23:58:40 1998 @@ -306,7 +306,7 @@ for(i=0;itmd_skb[i]) { - dev_kfree_skb(p->tmd_skb[i],FREE_WRITE); + dev_kfree_skb(p->tmd_skb[i]); p->tmd_skb[i] = NULL; } } @@ -548,7 +548,7 @@ if( (u32) virt_to_bus(ptr+size) > 0x1000000) { printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what); if(type) - kfree_skb(skb,FREE_WRITE); + kfree_skb(skb); else kfree(ptr); return NULL; @@ -623,7 +623,7 @@ kfree(p->tmdbounce[i]); #ifdef XMT_VIA_SKB if(p->tmd_skb[i]) - dev_kfree_skb(p->tmd_skb[i],FREE_WRITE); + dev_kfree_skb(p->tmd_skb[i]); #endif } @@ -631,7 +631,7 @@ { #ifdef RCV_VIA_SKB if(p->recv_skb[i]) - dev_kfree_skb(p->recv_skb[i],FREE_WRITE); + dev_kfree_skb(p->recv_skb[i]); #else if(p->recvbounce[i]) kfree(p->recvbounce[i]); @@ -741,7 +741,7 @@ struct tmd *tmdp = p->tmdhead + i; #ifdef XMT_VIA_SKB if(p->tmd_skb[i]) { - dev_kfree_skb(p->tmd_skb[i],FREE_WRITE); + dev_kfree_skb(p->tmd_skb[i]); p->tmd_skb[i] = NULL; } #endif @@ -955,7 +955,7 @@ #ifdef XMT_VIA_SKB if(p->tmd_skb[p->tmdlast]) { - dev_kfree_skb(p->tmd_skb[p->tmdlast],FREE_WRITE); + dev_kfree_skb(p->tmd_skb[p->tmdlast]); p->tmd_skb[p->tmdlast] = NULL; } #endif @@ -1104,7 +1104,7 @@ memcpy((char *) p->tmdbounce[p->tmdbouncenum] ,(char *)skb->data, (skb->len > T_BUF_SIZE) ? T_BUF_SIZE : skb->len); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); save_flags(flags); cli(); @@ -1202,10 +1202,10 @@ } disable_dma(dev_ni65.dma); free_dma(dev_ni65.dma); + unregister_netdev(&dev_ni65); release_region(dev_ni65.base_addr,cards[p->cardno].total_size); ni65_free_buffer(p); dev_ni65.priv = NULL; - unregister_netdev(&dev_ni65); } #endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/pcnet32.c new/linux/drivers/net/pcnet32.c --- old/linux/drivers/net/pcnet32.c Sat Nov 29 19:33:19 1997 +++ new/linux/drivers/net/pcnet32.c Tue Feb 10 21:56:45 1998 @@ -477,7 +477,7 @@ for (i = 0; i < TX_RING_SIZE; i++) { if (lp->tx_skbuff[i]) { - dev_kfree_skb(lp->tx_skbuff[i],FREE_WRITE); + dev_kfree_skb(lp->tx_skbuff[i]); lp->tx_skbuff[i] = NULL; } } @@ -707,7 +707,7 @@ /* We must free the original skb */ if (lp->tx_skbuff[entry]) { - dev_kfree_skb(lp->tx_skbuff[entry],FREE_WRITE); + dev_kfree_skb(lp->tx_skbuff[entry]); lp->tx_skbuff[entry] = 0; } dirty_tx++; diff -ur --new-file old/linux/drivers/net/plip.c new/linux/drivers/net/plip.c --- old/linux/drivers/net/plip.c Sun Jan 4 19:24:27 1998 +++ new/linux/drivers/net/plip.c Sat Feb 21 03:28:22 1998 @@ -80,7 +80,6 @@ */ #include -#include #include #include #include @@ -408,12 +407,12 @@ } rcv->state = PLIP_PK_DONE; if (rcv->skb) { - kfree_skb(rcv->skb, FREE_READ); + kfree_skb(rcv->skb); rcv->skb = NULL; } snd->state = PLIP_PK_DONE; if (snd->skb) { - dev_kfree_skb(snd->skb, FREE_WRITE); + dev_kfree_skb(snd->skb); snd->skb = NULL; } spin_unlock_irq(&nl->lock); @@ -742,7 +741,7 @@ &snd->nibble, snd->checksum)) return TIMEOUT; - dev_kfree_skb(snd->skb, FREE_WRITE); + dev_kfree_skb(snd->skb); nl->enet_stats.tx_packets++; snd->state = PLIP_PK_DONE; @@ -1011,12 +1010,12 @@ snd->state = PLIP_PK_DONE; if (snd->skb) { - dev_kfree_skb(snd->skb, FREE_WRITE); + dev_kfree_skb(snd->skb); snd->skb = NULL; } rcv->state = PLIP_PK_DONE; if (rcv->skb) { - kfree_skb(rcv->skb, FREE_READ); + kfree_skb(rcv->skb); rcv->skb = NULL; } diff -ur --new-file old/linux/drivers/net/ppp.c new/linux/drivers/net/ppp.c --- old/linux/drivers/net/ppp.c Tue Dec 23 19:57:31 1997 +++ new/linux/drivers/net/ppp.c Thu Mar 12 19:33:21 1998 @@ -3,11 +3,12 @@ * Michael Callahan * Al Longyear * Paul Mackerras + * Cyrus Durgin (changes for kmod) * * Dynamic PPP devices by Jim Freeman . * ppp_tty_receive ``noisy-raise-bug'' fixed by Ove Ewerlid * - * ==FILEVERSION 971205== + * ==FILEVERSION 980123== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the number above to the @@ -50,6 +51,7 @@ /* $Id: ppp.c,v 1.14 1997/11/27 06:04:45 paulus Exp $ */ +#include /* for CONFIG_KMOD */ #include #include #include @@ -93,8 +95,8 @@ #include #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif #ifndef PPP_IPX @@ -568,9 +570,7 @@ */ if (new_wbuf == NULL || new_tbuf == NULL || new_rbuf == NULL || new_cbuf == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp: failed to allocate new buffers\n"); + printk (KERN_ERR "ppp: failed to allocate new buffers\n"); ppp_free_buf (new_wbuf); ppp_free_buf (new_tbuf); @@ -685,13 +685,6 @@ if (tty != NULL && tty->disc_data == ppp) tty->disc_data = NULL; /* Break the tty->ppp link */ - rtnl_lock(); - /* Strong layering violation. */ - if (dev && dev->flags & IFF_UP) { - dev_close (dev); /* close the device properly */ - } - rtnl_unlock(); - ppp_free_buf (ppp->rbuf); ppp_free_buf (ppp->wbuf); ppp_free_buf (ppp->cbuf); @@ -770,8 +763,7 @@ * There should not be an existing table for this slot. */ if (ppp) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR + printk (KERN_ERR "ppp_tty_open: gack! tty already associated to %s!\n", ppp->magic == PPP_MAGIC ? ppp2dev(ppp)->name : "unknown"); @@ -793,8 +785,7 @@ } else { ppp = ppp_alloc(); if (ppp == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR "ppp_alloc failed\n"); + printk (KERN_ERR "ppp_alloc failed\n"); return -ENFILE; } /* @@ -808,9 +799,8 @@ */ ppp->slcomp = slhc_init (16, 16); if (ppp->slcomp == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR "ppp_tty_open: " - "no space for compression buffers!\n"); + printk (KERN_ERR "ppp_tty_open: " + "no space for compression buffers!\n"); ppp_release (ppp); return -ENOMEM; } @@ -826,9 +816,8 @@ */ ppp->ubuf = ppp_alloc_buf (RBUFSIZE, BUFFER_TYPE_TTY_RD); if (ppp->ubuf == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR "ppp_tty_open: " - "no space for user receive buffer\n"); + printk (KERN_ERR "ppp_tty_open: " + "no space for user receive buffer\n"); ppp_release (ppp); return -ENOMEM; } @@ -1300,9 +1289,7 @@ */ new_data = kmalloc (ppp->mru + PPP_HDRLEN, GFP_ATOMIC); if (new_data == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_doframe: no memory\n"); + printk (KERN_ERR "ppp_doframe: no memory\n"); new_count = DECOMP_ERROR; } else { new_count = (*ppp->sc_rcomp->decompress) @@ -1321,8 +1308,7 @@ case DECOMP_FATALERROR: ppp->flags |= SC_DC_FERROR; - if (ppp->flags & SC_DEBUG) - printk(KERN_ERR "ppp: fatal decomp error\n"); + printk(KERN_ERR "ppp: fatal decomp error\n"); break; } /* @@ -2069,15 +2055,16 @@ struct ppp *ppp = tty2ppp (tty); __u8 *new_data; int error; + struct wait_queue wait = {current, NULL}; /* * Verify the pointers. */ + error = -EIO; if (!ppp) - return -EIO; - + goto out; if (ppp->magic != PPP_MAGIC) - return -EIO; + goto out; CHECK_PPP (-ENXIO); /* @@ -2096,43 +2083,48 @@ */ new_data = kmalloc (count, GFP_KERNEL); if (new_data == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_write: no memory\n"); + printk (KERN_ERR "ppp_tty_write: no memory\n"); return 0; } /* * Retrieve the user's buffer */ - error = copy_from_user(new_data, data, count); - if (error) { - kfree (new_data); - return error; - } + error = -EFAULT; + if (copy_from_user(new_data, data, count)) + goto out_free; /* - * lock this PPP unit so we will be the only writer; - * sleep if necessary + * Lock this PPP unit so we will be the only writer, + * sleeping if necessary. + * + * Note that we add our task to the wait queue before + * attempting to lock, as the lock flag may be cleared + * from an interrupt. */ - while (lock_buffer (ppp->tbuf) != 0) { + add_wait_queue(&ppp->write_wait, &wait); + while (1) { + error = 0; current->timeout = 0; -#if 0 - if (ppp->flags & SC_DEBUG) - printk (KERN_DEBUG "ppp_tty_write: sleeping\n"); -#endif - interruptible_sleep_on (&ppp->write_wait); + current->state = TASK_INTERRUPTIBLE; + if (lock_buffer(ppp->tbuf) == 0) + break; + schedule(); + error = -EINVAL; ppp = tty2ppp (tty); - if (!ppp || ppp->magic != PPP_MAGIC || !ppp->inuse - || tty != ppp->tty) { - kfree (new_data); - return 0; - } - - if (signal_pending(current)) { - kfree (new_data); - return -EINTR; + if (!ppp || ppp->magic != PPP_MAGIC || + !ppp->inuse || tty != ppp->tty) { + printk("ppp_tty_write: %p invalid after wait!\n", ppp); + break; } + error = -EINTR; + if (signal_pending(current)) + break; } + current->state = TASK_RUNNING; + remove_wait_queue(&ppp->write_wait, &wait); + if (error) + goto out_free; + /* * Change the LQR frame */ @@ -2152,9 +2144,12 @@ } else { ppp_dev_xmit_frame (ppp, ppp->tbuf, new_data, count); } + error = count; +out_free: kfree (new_data); - return count; +out: + return error; } /* @@ -2165,31 +2160,30 @@ ppp_set_compression (struct ppp *ppp, struct ppp_option_data *odp) { struct compressor *cp; - struct ppp_option_data data; - int error; - int nb; + int error, nb; + unsigned long flags; __u8 *ptr; __u8 ccp_option[CCP_MAX_OPTION_LENGTH]; - unsigned long flags; + struct ppp_option_data data; /* * Fetch the compression parameters */ - error = copy_from_user(&data, odp, sizeof (data)); - if (error != 0) - return error; + error = -EFAULT; + if (copy_from_user(&data, odp, sizeof (data))) + goto out; nb = data.length; ptr = data.ptr; if ((__u32) nb >= (__u32)CCP_MAX_OPTION_LENGTH) nb = CCP_MAX_OPTION_LENGTH; - error = copy_from_user(ccp_option, ptr, nb); - if (error != 0) - return error; + if (copy_from_user(ccp_option, ptr, nb)) + goto out; + error = -EINVAL; if (ccp_option[1] < 2) /* preliminary check on the length byte */ - return (-EINVAL); + goto out; save_flags(flags); cli(); @@ -2197,62 +2191,61 @@ restore_flags(flags); cp = find_compressor (ccp_option[0]); -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (cp == NULL) { char modname[32]; sprintf(modname, "ppp-compress-%d", ccp_option[0]); request_module(modname); cp = find_compressor(ccp_option[0]); } -#endif /* CONFIG_KERNELD */ +#endif /* CONFIG_KMOD */ - if (cp != (struct compressor *) 0) { - /* - * Found a handler for the protocol - try to allocate - * a compressor or decompressor. - */ - error = 0; - if (data.transmit) { - if (ppp->sc_xc_state != NULL) - (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); + if (cp == NULL) + goto out_no_comp; + /* + * Found a handler for the protocol - try to allocate + * a compressor or decompressor. + */ + error = 0; + if (data.transmit) { + if (ppp->sc_xc_state != NULL) + (*ppp->sc_xcomp->comp_free)(ppp->sc_xc_state); + ppp->sc_xc_state = NULL; - ppp->sc_xcomp = cp; - ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb); + ppp->sc_xcomp = cp; + ppp->sc_xc_state = cp->comp_alloc(ccp_option, nb); + if (ppp->sc_xc_state == NULL) { + printk(KERN_WARNING "%s: comp_alloc failed\n", + ppp->name); + error = -ENOBUFS; + } else if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: comp_alloc -> %p\n", + ppp->name, ppp->sc_xc_state); + } else { + if (ppp->sc_rc_state != NULL) + (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state); + ppp->sc_rc_state = NULL; - if (ppp->sc_xc_state == NULL) { - if (ppp->flags & SC_DEBUG) - printk(KERN_DEBUG "%s: comp_alloc failed\n", - ppp->name); - error = -ENOBUFS; - } else { - if (ppp->flags & SC_DEBUG) - printk(KERN_DEBUG "%s: comp_alloc -> %p\n", - ppp->name, ppp->sc_xc_state); - } - } else { - if (ppp->sc_rc_state != NULL) - (*ppp->sc_rcomp->decomp_free)(ppp->sc_rc_state); - ppp->sc_rcomp = cp; - ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb); - if (ppp->sc_rc_state == NULL) { - if (ppp->flags & SC_DEBUG) - printk(KERN_DEBUG "%s: decomp_alloc failed\n", - ppp->name); - error = -ENOBUFS; - } else { - if (ppp->flags & SC_DEBUG) - printk(KERN_DEBUG "%s: decomp_alloc -> %p\n", - ppp->name, ppp->sc_rc_state); - } - } - return (error); + ppp->sc_rcomp = cp; + ppp->sc_rc_state = cp->decomp_alloc(ccp_option, nb); + if (ppp->sc_rc_state == NULL) { + printk(KERN_WARNING "%s: decomp_alloc failed\n", + ppp->name); + error = -ENOBUFS; + } else if (ppp->flags & SC_DEBUG) + printk(KERN_DEBUG "%s: decomp_alloc -> %p\n", + ppp->name, ppp->sc_rc_state); } +out: + return error; +out_no_comp: + error = -EINVAL; /* no handler found */ if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "%s: no compressor for [%x %x %x], %x\n", - ppp->name, ccp_option[0], ccp_option[1], - ccp_option[2], nb); - return (-EINVAL); /* no handler found */ + ppp->name, ccp_option[0], ccp_option[1], + ccp_option[2], nb); + goto out; } /* @@ -2409,16 +2402,20 @@ /* change absolute times to relative times. */ cur_ddinfo.xmit_idle = (jiffies - ppp->last_xmit) / HZ; cur_ddinfo.recv_idle = (jiffies - ppp->last_recv) / HZ; - error = copy_to_user((void *) param3, &cur_ddinfo, - sizeof (cur_ddinfo)); + error = -EFAULT; + if (!copy_to_user((void *) param3, &cur_ddinfo, + sizeof (cur_ddinfo))) + error = 0; } break; /* * Retrieve the extended async map */ case PPPIOCGXASYNCMAP: - error = copy_to_user((void *) param3, ppp->xmit_async_map, - sizeof (ppp->xmit_async_map)); + error = -EFAULT; + if (!copy_to_user((void *) param3, ppp->xmit_async_map, + sizeof (ppp->xmit_async_map))) + error = 0; break; /* * Set the async extended map @@ -2427,15 +2424,16 @@ { __u32 temp_tbl[8]; - error = copy_from_user(temp_tbl, (void *) param3, - sizeof (temp_tbl)); - if (error != 0) + error = -EFAULT; + if (copy_from_user(temp_tbl, (void *) param3, + sizeof (temp_tbl))) break; temp_tbl[1] = 0x00000000; temp_tbl[2] &= ~0x40000000; temp_tbl[3] |= 0x60000000; + error = 0; if ((temp_tbl[2] & temp_tbl[3]) != 0 || (temp_tbl[4] & temp_tbl[5]) != 0 || (temp_tbl[6] & temp_tbl[7]) != 0) @@ -2461,16 +2459,15 @@ temp_i = (temp_i & 255) + 1; if (ppp->flags & SC_DEBUG) printk (KERN_INFO - "ppp_tty_ioctl: set maxcid to %d\n", - temp_i); + "ppp_tty_ioctl: set maxcid to %d\n", temp_i); if (ppp->slcomp != NULL) slhc_free (ppp->slcomp); - ppp->slcomp = slhc_init (16, temp_i); + ppp->slcomp = NULL; + ppp->slcomp = slhc_init (16, temp_i); if (ppp->slcomp == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp: no space for compression buffers!\n"); + printk (KERN_ERR "ppp_tty_ioctl: " + "no space for compression buffers!\n"); ppp_release (ppp); error = -ENOMEM; } @@ -2486,39 +2483,35 @@ { struct npioctl npi; - error = copy_from_user(&npi, (void *) param3, - sizeof (npi)); - if (error != 0) + error = -EFAULT; + if (copy_from_user(&npi, (void *) param3, sizeof(npi))) break; - switch (npi.protocol) { - case PPP_IP: - npi.protocol = NP_IP; - break; - default: + if (npi.protocol != PPP_IP) { if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "pppioc[gs]npmode: " - "invalid proto %d\n", npi.protocol); + "invalid protocol %d\n", + npi.protocol); error = -EINVAL; - } - - if (error != 0) break; + } + npi.protocol = NP_IP; if (param2 == PPPIOCGNPMODE) { npi.mode = ppp->sc_npmode[npi.protocol]; - - error = copy_to_user((void *) param3, &npi, - sizeof (npi)); - break; + if (copy_to_user((void *) param3, &npi, + sizeof (npi))) + break; } ppp->sc_npmode[npi.protocol] = npi.mode; if (ppp->flags & SC_DEBUG) printk(KERN_DEBUG "ppp: set np %d to %d\n", npi.protocol, npi.mode); + /* N.B. Why is the busy flag cleared here? */ ppp2dev(ppp)->tbusy = 0; mark_bh(NET_BH); + error = 0; } break; /* @@ -2542,11 +2535,8 @@ */ default: if (ppp->flags & SC_DEBUG) - printk (KERN_ERR - "ppp_tty_ioctl: invalid ioctl: %x, addr %lx\n", - param2, - param3); - + printk (KERN_WARNING "ppp_tty_ioctl: " + "invalid ioctl=%x, addr=%lx\n", param2, param3); error = -ENOIOCTLCMD; break; } @@ -2568,8 +2558,8 @@ if (ppp && ppp->magic == PPP_MAGIC && tty == ppp->tty) { CHECK_PPP (0); - poll_wait(&ppp->read_wait, wait); - poll_wait(&ppp->write_wait, wait); + poll_wait(filp, &ppp->read_wait, wait); + poll_wait(filp, &ppp->write_wait, wait); /* Must lock the user buffer area while checking. */ CHECK_BUF_MAGIC(ppp->ubuf); @@ -2606,8 +2596,7 @@ struct ppp *ppp = dev2ppp (dev); if (ppp2tty (ppp) == NULL) { - if (ppp->flags & SC_DEBUG) - printk (KERN_ERR + printk (KERN_ERR "ppp: %s not connected to a TTY! can't go open!\n", dev->name); return -ENXIO; @@ -2659,8 +2648,9 @@ /* * Move the version data */ - error = copy_to_user(result, szVersion, len); - + error = -EFAULT; + if (!copy_to_user(result, szVersion, len)) + error = 0; return error; } @@ -2695,8 +2685,9 @@ result = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; - error = copy_to_user(result, &temp, sizeof (temp)); - + error = -EFAULT; + if (!copy_to_user(result, &temp, sizeof (temp))) + error = 0; return error; } @@ -2727,8 +2718,9 @@ */ result = (struct ppp_comp_stats *) ifr->ifr_ifru.ifru_data; - error = copy_to_user(result, &temp, sizeof (temp)); - + error = -EFAULT; + if (!copy_to_user(result, &temp, sizeof (temp))) + error = 0; return error; } @@ -2895,7 +2887,7 @@ * Avoid timing problem should tty hangup while data is queued to be sent */ if (!ppp->inuse) { - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } /* @@ -2906,7 +2898,7 @@ printk (KERN_ERR "ppp_dev_xmit: %s not connected to a TTY!\n", dev->name); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } /* @@ -2919,7 +2911,7 @@ if (ppp->flags & SC_DEBUG) printk (KERN_CRIT "ppp_dev_xmit: %s Null skb data\n", dev->name); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } /* @@ -2960,7 +2952,7 @@ break; default: /* All others have no support at this time. */ - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); return 0; } /* @@ -2968,12 +2960,12 @@ */ if (answer == 0) { /* packet queued OK */ - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); } else { ppp->wbuf->locked = 0; if (answer < 0) { /* packet should be dropped */ - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); answer = 0; } else { /* packet should be queued for later */ @@ -3023,6 +3015,25 @@ return ppp; } +/* Collect hanged up channels */ + +static void ppp_sync(void) +{ + struct device *dev; + struct ppp *ppp; + + rtnl_lock(); + for (ppp = ppp_list; ppp != 0; ppp = ppp->next) { + if (!ppp->inuse) { + dev = ppp2dev(ppp); + if (dev->flags&IFF_UP) + dev_close(dev); + } + } + rtnl_unlock(); +} + + /* allocate or create a PPP channel */ static struct ppp * ppp_alloc (void) @@ -3032,11 +3043,24 @@ struct device *dev; struct ppp *ppp; + ppp_sync(); + /* try to find an free device */ if_num = 0; for (ppp = ppp_list; ppp != 0; ppp = ppp->next) { - if (!test_and_set_bit(0, &ppp->inuse)) + if (!test_and_set_bit(0, &ppp->inuse)) { + + /* Reregister device */ + + dev = ppp2dev(ppp); + unregister_netdev (dev); + + if (register_netdev (dev)) { + printk(KERN_DEBUG "cannot reregister ppp device\n"); + return NULL; + } return ppp; + } ++if_num; } /* 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 Tue Dec 23 19:57:31 1997 +++ new/linux/drivers/net/ppp_deflate.c Tue Feb 10 21:56:45 1998 @@ -188,20 +188,20 @@ struct ppp_deflate_state *state; int w_size; + MOD_INC_USE_COUNT; if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE || options[1] != CILEN_DEFLATE || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || options[3] != DEFLATE_CHK_SEQUENCE) - return NULL; + goto out_fail; w_size = DEFLATE_SIZE(options[2]); if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) - return NULL; + goto out_fail; state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) - return NULL; + goto out_fail; - MOD_INC_USE_COUNT; memset (state, 0, sizeof (struct ppp_deflate_state)); state->strm.next_in = NULL; state->strm.zalloc = zalloc_init; @@ -210,13 +210,16 @@ if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY) - != Z_OK) { - z_comp_free(state); - return NULL; - } - + != Z_OK) + goto out_free; state->strm.zalloc = zalloc; return (void *) state; + +out_free: + z_comp_free(state); +out_fail: + MOD_DEC_USE_COUNT; + return NULL; } static int @@ -369,33 +372,35 @@ struct ppp_deflate_state *state; int w_size; + MOD_INC_USE_COUNT; if (opt_len != CILEN_DEFLATE || options[0] != CI_DEFLATE || options[1] != CILEN_DEFLATE || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || options[3] != DEFLATE_CHK_SEQUENCE) - return NULL; + goto out_fail; w_size = DEFLATE_SIZE(options[2]); if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) - return NULL; + goto out_fail; state = (struct ppp_deflate_state *) kmalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) - return NULL; - - MOD_INC_USE_COUNT; + goto out_fail; memset (state, 0, sizeof (struct ppp_deflate_state)); state->w_size = w_size; state->strm.next_out = NULL; state->strm.zalloc = zalloc_init; state->strm.zfree = zfree; - if (inflateInit2(&state->strm, -w_size) != Z_OK) { - z_decomp_free(state); - return NULL; - } - + if (inflateInit2(&state->strm, -w_size) != Z_OK) + goto out_free; state->strm.zalloc = zalloc; return (void *) state; + +out_free: + z_decomp_free(state); +out_fail: + MOD_DEC_USE_COUNT; + return NULL; } static int diff -ur --new-file old/linux/drivers/net/sdla.c new/linux/drivers/net/sdla.c --- old/linux/drivers/net/sdla.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/net/sdla.c Sat Feb 21 03:28:22 1998 @@ -32,6 +32,7 @@ * 2 of the License, or (at your option) any later version. */ +#include /* for CONFIG_DLCI_MAX */ #include #include diff -ur --new-file old/linux/drivers/net/sdla_fr.c new/linux/drivers/net/sdla_fr.c --- old/linux/drivers/net/sdla_fr.c Mon Jan 12 23:46:16 1998 +++ new/linux/drivers/net/sdla_fr.c Tue Feb 10 21:56:45 1998 @@ -1,4 +1,4 @@ -/***************************************************************************** +/**************************************************************************** * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * * Author(s): Gene Kozin @@ -673,9 +673,8 @@ /* Set transmit buffer queue length */ dev->tx_queue_len = 30; - /* Initialize socket buffers */ - for (i = 0; i < DEV_NUMBUFFS; ++i) - skb_queue_head_init(&dev->buffs[i]); + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -966,7 +965,7 @@ printk(KERN_INFO "%s: if_send() hit critical section!\n", card->devname); #endif - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } disable_irq(card->hw.irq); @@ -1021,7 +1020,7 @@ ++chan->if_send_critical_non_ISR; ++chan->ifstats.tx_dropped; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); save_flags(host_cpu_flags); cli(); if ((!(--card->irq_dis_if_send_count)) && @@ -1113,7 +1112,7 @@ } if (!retry) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); card->wandev.critical = 0; save_flags(host_cpu_flags); @@ -1448,7 +1447,7 @@ buf = skb_pull(skb, 1); /* remove hardware header */ if (!wan_type_trans(skb, dev)) { /* can't decapsulate packet */ - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); ++chan->ifstats.rx_errors; ++card->wandev.stats.rx_errors; } else { @@ -1565,7 +1564,7 @@ if (!wan_type_trans(skb, dev)) { /* can't decapsulate packet */ - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); ++chan->rx_intr_bfr_not_passed_to_stack; ++chan->ifstats.rx_errors; ++card->wandev.stats.rx_errors; diff -ur --new-file old/linux/drivers/net/sdla_ppp.c new/linux/drivers/net/sdla_ppp.c --- old/linux/drivers/net/sdla_ppp.c Mon Jan 12 23:46:16 1998 +++ new/linux/drivers/net/sdla_ppp.c Sat Feb 21 03:28:22 1998 @@ -59,6 +59,7 @@ #error This code MUST be compiled as a kernel module! #endif +#include /* CONFIG_SANGOMA_MANAGER */ #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ @@ -478,9 +479,8 @@ dev->tx_queue_len = 100; /* Initialize socket buffers */ - for (i = 0; i < DEV_NUMBUFFS; ++i) - skb_queue_head_init(&dev->buffs[i]); - + dev_init_buffers(dev); + return 0; } @@ -698,7 +698,7 @@ #ifdef CONFIG_SANGOMA_MANAGER if(sangoma_ppp_manager(skb,card)) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } #endif @@ -733,7 +733,7 @@ } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); ++ppp_priv_area->if_send_critical_non_ISR; save_flags(host_cpu_flags); @@ -787,7 +787,7 @@ tx_done: if (!retry){ - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } card->wandev.critical = 0; @@ -1281,21 +1281,21 @@ process_udp_driver_call( UDP_PKT_FRM_NETWORK, card, skb, dev, ppp_priv_area); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } else if (udp_type == UDP_PTPIPE_TYPE){ ++ppp_priv_area->rx_intr_PTPIPE_request; err = process_udp_mgmt_pkt( UDP_PKT_FRM_NETWORK, card, skb, dev, ppp_priv_area); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } else #endif if (handle_IPXWAN(skb->data,card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) { if( card->wandev.enable_IPX) { ppp_send(card, skb->data, skb->len, ETH_P_IPX); - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); } else { ++card->wandev.stats.rx_dropped; diff -ur --new-file old/linux/drivers/net/sdla_x25.c new/linux/drivers/net/sdla_x25.c --- old/linux/drivers/net/sdla_x25.c Mon Jan 12 23:46:16 1998 +++ new/linux/drivers/net/sdla_x25.c Tue Feb 10 21:56:45 1998 @@ -572,9 +572,8 @@ dev->tx_queue_len = 10; /* Initialize socket buffers */ - for (i = 0; i < DEV_NUMBUFFS; ++i) - skb_queue_head_init(&dev->buffs[i]) - ; + dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -760,7 +759,7 @@ return dev->tbusy; } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); save_flags(host_cpu_flags); cli(); @@ -833,7 +832,7 @@ tx_done: if (!dev->tbusy) { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } card->wandev.critical = 0; save_flags(host_cpu_flags); @@ -1001,7 +1000,7 @@ if (skb_tailroom(skb) < len) { /* No room for the packet. Call off the whole thing! */ - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); chan->rx_skb = NULL; if (qdm & 0x01) chan->drop_sequence = 1; @@ -1024,7 +1023,7 @@ if (!skb->protocol && !wan_type_trans(skb, dev)) { /* can't decapsulate packet */ - dev_kfree_skb(skb, FREE_READ); + dev_kfree_skb(skb); ++chan->ifstats.rx_errors; } else @@ -1039,7 +1038,7 @@ } else { - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } } else @@ -1212,7 +1211,7 @@ { chan->tx_skb = NULL; dev->tbusy = 0; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } /* If SVC has been idle long enough, close virtual circuit */ diff -ur --new-file old/linux/drivers/net/sdladrv.c new/linux/drivers/net/sdladrv.c --- old/linux/drivers/net/sdladrv.c Thu Apr 24 04:01:20 1997 +++ new/linux/drivers/net/sdladrv.c Sat Feb 21 03:28:22 1998 @@ -81,7 +81,6 @@ #if defined(_LINUX_) /****** Linux *******************************/ -#include /* OS configuration options */ #include /* printk(), and other useful stuff */ #include /* offsetof(), etc. */ #include /* return codes */ diff -ur --new-file old/linux/drivers/net/seeq8005.c new/linux/drivers/net/seeq8005.c --- old/linux/drivers/net/seeq8005.c Mon Nov 3 18:29:30 1997 +++ new/linux/drivers/net/seeq8005.c Mon Mar 16 23:17:29 1998 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -209,10 +210,7 @@ #endif outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */ - SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; - SLOW_DOWN_IO; + udelay(5); outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD); if (net_debug) { @@ -400,7 +398,7 @@ hardware_send_packet(dev, buf, length); dev->trans_start = jiffies; } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ @@ -626,10 +624,7 @@ int i; outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */ - SLOW_DOWN_IO; /* have to wait 4us after a reset - should be fixed */ - SLOW_DOWN_IO; - SLOW_DOWN_IO; - SLOW_DOWN_IO; + udelay(5); outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */ @@ -638,7 +633,7 @@ for(i=0;i<6;i++) { /* set Station address */ outb(dev->dev_addr[i], SEEQ_BUFFER); - SLOW_DOWN_IO; + udelay(2); } outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */ diff -ur --new-file old/linux/drivers/net/sgiseeq.c new/linux/drivers/net/sgiseeq.c --- old/linux/drivers/net/sgiseeq.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/net/sgiseeq.c Tue Feb 10 21:56:45 1998 @@ -570,7 +570,7 @@ hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; } dev->trans_start = jiffies; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); if(TX_BUFFS_AVAIL(sp)) dev->tbusy = 0; diff -ur --new-file old/linux/drivers/net/shaper.c new/linux/drivers/net/shaper.c --- old/linux/drivers/net/shaper.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/net/shaper.c Sun Mar 1 23:40:39 1998 @@ -70,6 +70,7 @@ #include #include #include +#include #include int sh_debug; /* Debug flag */ @@ -190,7 +191,7 @@ if(ptr->shapelatency > SHAPER_LATENCY) { skb_unlink(ptr); - dev_kfree_skb(ptr, FREE_WRITE); + dev_kfree_skb(ptr); } ptr=tmp; } @@ -225,7 +226,7 @@ * Queue over time. Spill packet. */ if(skb->shapeclock-jiffies > SHAPER_LATENCY) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); else skb_queue_tail(&shaper->sendq, skb); } @@ -235,7 +236,7 @@ if(skb_queue_len(&shaper->sendq)>SHAPER_QLEN) { ptr=skb_dequeue(&shaper->sendq); - dev_kfree_skb(ptr, FREE_WRITE); + dev_kfree_skb(ptr); } shaper_unlock(shaper); shaper_kick(shaper); @@ -254,7 +255,6 @@ if(newskb) { newskb->dev=shaper->dev; - newskb->arp=1; newskb->priority=2; if(sh_debug) printk("Kick new frame to %s, %d\n", @@ -262,7 +262,7 @@ dev_queue_xmit(newskb); if(sh_debug) printk("Kicked new frame out.\n"); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } } @@ -369,7 +369,7 @@ { struct sk_buff *skb; while((skb=skb_dequeue(&shaper->sendq))!=NULL) - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } /* @@ -448,17 +448,18 @@ return v; } -static int shaper_cache(struct dst_entry *dst, struct neighbour *neigh, struct hh_cache *hh) +#if 0 +static int shaper_cache(struct neighbour *neigh, struct hh_cache *hh) { - struct shaper *sh=dst->dev->priv; + struct shaper *sh=neigh->dev->priv; struct device *tmp; int ret; if(sh_debug) printk("Shaper header cache bind\n"); - tmp=dst->dev; - dst->dev=sh->dev; - ret=sh->hard_header_cache(dst,neigh,hh); - dst->dev=tmp; + tmp=neigh->dev; + neigh->dev=sh->dev; + ret=sh->hard_header_cache(neigh,hh); + neigh->dev=tmp; return ret; } @@ -470,6 +471,26 @@ printk("Shaper cache update\n"); sh->header_cache_update(hh, sh->dev, haddr); } +#endif + +static int shaper_neigh_setup(struct neighbour *n) +{ + if (n->nud_state == NUD_NONE) { + n->ops = &arp_broken_ops; + n->output = n->ops->output; + } + return 0; +} + +static int shaper_neigh_setup_dev(struct device *dev, struct neigh_parms *p) +{ + if (p->tbl->family == AF_INET) { + p->neigh_setup = shaper_neigh_setup; + p->ucast_probes = 0; + p->mcast_probes = 0; + } + return 0; +} static int shaper_attach(struct device *shdev, struct shaper *sh, struct device *dev) { @@ -513,7 +534,8 @@ #else shdev->header_cache_update = NULL; shdev->hard_header_cache = NULL; -#endif +#endif + shdev->neigh_setup = shaper_neigh_setup_dev; shdev->hard_header_len=dev->hard_header_len; shdev->type=dev->type; @@ -588,8 +610,11 @@ dev->hard_header = shaper_header; dev->rebuild_header = shaper_rebuild_header; +#if 0 dev->hard_header_cache = shaper_cache; dev->header_cache_update= shaper_cache_update; +#endif + dev->neigh_setup = shaper_neigh_setup_dev; dev->do_ioctl = shaper_ioctl; dev->hard_header_len = 0; dev->type = ARPHRD_ETHER; /* initially */ 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 Nov 3 18:29:31 1997 +++ new/linux/drivers/net/sk_g16.c Tue Feb 10 21:56:45 1998 @@ -1251,7 +1251,7 @@ dev->tbusy = 0; } } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } /* End of SK_send_packet */ diff -ur --new-file old/linux/drivers/net/skeleton.c new/linux/drivers/net/skeleton.c --- old/linux/drivers/net/skeleton.c Mon Nov 3 18:29:31 1997 +++ new/linux/drivers/net/skeleton.c Tue Feb 10 21:56:45 1998 @@ -374,7 +374,7 @@ hardware_send_packet(ioaddr, buf, length); dev->trans_start = jiffies; } - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); /* You might need to clean up and record Tx statistics here. */ if (inw(ioaddr) == /*RU*/81) diff -ur --new-file old/linux/drivers/net/slhc.c new/linux/drivers/net/slhc.c --- old/linux/drivers/net/slhc.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/net/slhc.c Tue Feb 10 21:56:45 1998 @@ -99,21 +99,18 @@ register struct cstate *ts; struct slcompress *comp; + MOD_INC_USE_COUNT; comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), GFP_KERNEL); if (! comp) - return NULL; - + goto out_fail; memset(comp, 0, sizeof(struct slcompress)); if ( rslots > 0 && rslots < 256 ) { size_t rsize = rslots * sizeof(struct cstate); comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); if (! comp->rstate) - { - kfree((unsigned char *)comp); - return NULL; - } + goto out_free; memset(comp->rstate, 0, rsize); comp->rslot_limit = rslots - 1; } @@ -122,11 +119,7 @@ size_t tsize = tslots * sizeof(struct cstate); comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); if (! comp->tstate) - { - kfree((unsigned char *)comp->rstate); - kfree((unsigned char *)comp); - return NULL; - } + goto out_free2; memset(comp->tstate, 0, tsize); comp->tslot_limit = tslots - 1; } @@ -151,8 +144,15 @@ ts[0].next = &(ts[comp->tslot_limit]); ts[0].cs_this = 0; } - MOD_INC_USE_COUNT; return comp; + +out_free2: + kfree((unsigned char *)comp->rstate); +out_free: + kfree((unsigned char *)comp); +out_fail: + MOD_DEC_USE_COUNT; + return NULL; } @@ -163,14 +163,14 @@ if ( comp == NULLSLCOMPR ) return; - if ( comp->rstate != NULLSLSTATE ) - kfree( comp->rstate ); - if ( comp->tstate != NULLSLSTATE ) kfree( comp->tstate ); - MOD_DEC_USE_COUNT; + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + kfree( comp ); + MOD_DEC_USE_COUNT; } diff -ur --new-file old/linux/drivers/net/slip.c new/linux/drivers/net/slip.c --- old/linux/drivers/net/slip.c Sun Nov 30 23:00:38 1997 +++ new/linux/drivers/net/slip.c Tue Mar 10 18:47:26 1998 @@ -50,6 +50,8 @@ * from multislip BSDI driver which was written * by Igor Chechik, RELCOM Corp. Only algorithms * have been ported to Linux SLIP driver. + * Vitaly E. Lavrov : Sane behaviour on tty hangup. + * Alexey Kuznetsov : Cleanup interfaces to tty&netdevice modules. */ #define SL_CHECK_TRANSMIT @@ -110,133 +112,141 @@ static int sl_ioctl(struct device *dev,struct ifreq *rq,int cmd); #endif -/* Find a free SLIP channel, and link in this `tty' line. */ -static inline struct slip * -sl_alloc(void) -{ - slip_ctrl_t *slp = NULL; - int i; - - if (slip_ctrls == NULL) return NULL; /* Master array missing ! */ - - for (i = 0; i < slip_maxdev; i++) { - slp = slip_ctrls[i]; - /* Not allocated ? */ - if (slp == NULL) - break; - /* Not in use ? */ - if (!test_and_set_bit(SLF_INUSE, &slp->ctrl.flags)) - break; - } - /* SLP is set.. */ - - /* Sorry, too many, all slots in use */ - if (i >= slip_maxdev) return NULL; - - /* If no channels are available, allocate one */ - if (!slp && - (slip_ctrls[i] = (slip_ctrl_t *)kmalloc(sizeof(slip_ctrl_t), - GFP_KERNEL)) != NULL) { - slp = slip_ctrls[i]; - memset(slp, 0, sizeof(slip_ctrl_t)); - - /* Initialize channel control data */ - set_bit(SLF_INUSE, &slp->ctrl.flags); - slp->ctrl.tty = NULL; - sprintf(slp->if_name, "sl%d", i); - slp->dev.name = slp->if_name; - slp->dev.base_addr = i; - slp->dev.priv = (void*)&(slp->ctrl); - slp->dev.next = NULL; - slp->dev.init = slip_init; -/* printk(KERN_INFO "slip: kmalloc()ed SLIP control node for line %s\n", - slp->if_name); */ - } - if (slp != NULL) { +/******************************** +* Buffer administration routines: +* sl_alloc_bufs() +* sl_free_bufs() +* sl_realloc_bufs() +* +* NOTE: sl_realloc_bufs != sl_free_bufs + sl_alloc_bufs, because +* sl_realloc_bufs provides strong atomicity and reallocation +* on actively running device. +*********************************/ - /* register device so that it can be ifconfig'ed */ - /* slip_init() will be called as a side-effect */ - /* SIDE-EFFECT WARNING: slip_init() CLEARS slp->ctrl ! */ - - if (register_netdev(&(slp->dev)) == 0) { - /* (Re-)Set the INUSE bit. Very Important! */ - set_bit(SLF_INUSE, &slp->ctrl.flags); - slp->ctrl.dev = &(slp->dev); - slp->dev.priv = (void*)&(slp->ctrl); +/* + Allocate channel buffers. + */ -/* printk(KERN_INFO "slip: linked in netdev %s for active use\n", - slp->if_name); */ +static int +sl_alloc_bufs(struct slip *sl, int mtu) +{ + int err = -ENOBUFS; + unsigned long len; + char * rbuff = NULL; + char * xbuff = NULL; +#ifdef SL_INCLUDE_CSLIP + char * cbuff = NULL; + struct slcompress *slcomp = NULL; +#endif - return (&(slp->ctrl)); + /* + * Allocate the SLIP frame buffers: + * + * rbuff Receive buffer. + * xbuff Transmit buffer. + * cbuff Temporary compression buffer. + */ + len = mtu * 2; - } else { - clear_bit(SLF_INUSE,&(slp->ctrl.flags)); - printk("sl_alloc() - register_netdev() failure.\n"); - } + /* + * allow for arrival of larger UDP packets, even if we say not to + * also fixes a bug in which SunOS sends 512-byte packets even with + * an MSS of 128 + */ + if (len < 576 * 2) + len = 576 * 2; + rbuff = kmalloc(len + 4, GFP_KERNEL); + if (rbuff == NULL) + goto err_exit; + xbuff = kmalloc(len + 4, GFP_KERNEL); + if (xbuff == NULL) + goto err_exit; +#ifdef SL_INCLUDE_CSLIP + cbuff = kmalloc(len + 4, GFP_KERNEL); + if (cbuff == NULL) + goto err_exit; + slcomp = slhc_init(16, 16); + if (slcomp == NULL) + goto err_exit; +#endif + start_bh_atomic(); + if (sl->tty == NULL) { + end_bh_atomic(); + err = -ENODEV; + goto err_exit; } + sl->mtu = mtu; + sl->buffsize = len; + sl->rcount = 0; + sl->xleft = 0; + rbuff = xchg(&sl->rbuff, rbuff); + xbuff = xchg(&sl->xbuff, xbuff); +#ifdef SL_INCLUDE_CSLIP + cbuff = xchg(&sl->cbuff, cbuff); + slcomp = xchg(&sl->slcomp, slcomp); +#ifdef CONFIG_SLIP_MODE_SLIP6 + sl->xdata = 0; + sl->xbits = 0; +#endif +#endif + end_bh_atomic(); + err = 0; - return NULL; + /* Cleanup */ +err_exit: +#ifdef SL_INCLUDE_CSLIP + if (cbuff) + kfree(cbuff); + if (slcomp) + slhc_free(slcomp); +#endif + if (xbuff) + kfree(xbuff); + if (rbuff) + kfree(rbuff); + return err; } - -/* Free a SLIP channel. */ -static inline void -sl_free(struct slip *sl) +/* Free a SLIP channel buffers. */ +static void +sl_free_bufs(struct slip *sl) { + void * tmp; + /* Free all SLIP frame buffers. */ - if (sl->rbuff) { - kfree(sl->rbuff); - } - sl->rbuff = NULL; - if (sl->xbuff) { - kfree(sl->xbuff); - } - sl->xbuff = NULL; + if ((tmp = xchg(&sl->rbuff, NULL)) != NULL) + kfree(tmp); + if ((tmp = xchg(&sl->xbuff, NULL)) != NULL) + kfree(tmp); #ifdef SL_INCLUDE_CSLIP - /* Save CSLIP statistics */ - if (sl->slcomp) { - sl->rx_compressed += sl->slcomp->sls_i_compressed; - sl->rx_dropped += sl->slcomp->sls_i_tossed; - sl->tx_compressed += sl->slcomp->sls_o_compressed; - sl->tx_misses += sl->slcomp->sls_o_misses; - } - if (sl->cbuff) { - kfree(sl->cbuff); - } - sl->cbuff = NULL; - if(sl->slcomp) - slhc_free(sl->slcomp); - sl->slcomp = NULL; + if ((tmp = xchg(&sl->cbuff, NULL)) != NULL) + kfree(tmp); + if ((tmp = xchg(&sl->slcomp, NULL)) != NULL) + slhc_free(tmp); #endif - - if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) { - printk("%s: sl_free for already free unit.\n", sl->dev->name); - } } -/* MTU has been changed by the IP layer. Unfortunately we are not told - about this, but we spot it ourselves and fix things up. We could be - in an upcall from the tty driver, or in an ip packet queue. */ +/* + Reallocate slip channel buffers. + */ -static void sl_changedmtu(struct slip *sl) +static int sl_realloc_bufs(struct slip *sl, int mtu) { + int err = 0; struct device *dev = sl->dev; - unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; + unsigned char *xbuff, *rbuff; #ifdef SL_INCLUDE_CSLIP - unsigned char *cbuff, *ocbuff; + unsigned char *cbuff; #endif - int len; - unsigned long flags; + int len = mtu * 2; - len = dev->mtu * 2; /* * allow for arrival of larger UDP packets, even if we say not to * also fixes a bug in which SunOS sends 512-byte packets even with * an MSS of 128 */ - if (len < 576 * 2) { + if (len < 576 * 2) len = 576 * 2; - } xbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); @@ -244,37 +254,30 @@ cbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); #endif + #ifdef SL_INCLUDE_CSLIP if (xbuff == NULL || rbuff == NULL || cbuff == NULL) { #else if (xbuff == NULL || rbuff == NULL) { #endif - printk("%s: unable to grow slip buffers, MTU change cancelled.\n", - sl->dev->name); - dev->mtu = sl->mtu; - if (xbuff != NULL) { - kfree(xbuff); - } - if (rbuff != NULL) { - kfree(rbuff); + if (mtu >= sl->mtu) { + printk("%s: unable to grow slip buffers, MTU change cancelled.\n", + dev->name); + err = -ENOBUFS; } -#ifdef SL_INCLUDE_CSLIP - if (cbuff != NULL) { - kfree(cbuff); - } -#endif - return; + goto done; } - save_flags(flags); cli(); + start_bh_atomic(); + + err = -ENODEV; + if (sl->tty == NULL) + goto done_on_bh; - oxbuff = sl->xbuff; - sl->xbuff = xbuff; - orbuff = sl->rbuff; - sl->rbuff = rbuff; + xbuff = xchg(&sl->xbuff, xbuff); + rbuff = xchg(&sl->rbuff, rbuff); #ifdef SL_INCLUDE_CSLIP - ocbuff = sl->cbuff; - sl->cbuff = cbuff; + cbuff = xchg(&sl->cbuff, cbuff); #endif if (sl->xleft) { if (sl->xleft <= len) { @@ -288,30 +291,31 @@ if (sl->rcount) { if (sl->rcount <= len) { - memcpy(sl->rbuff, orbuff, sl->rcount); + memcpy(sl->rbuff, rbuff, sl->rcount); } else { sl->rcount = 0; sl->rx_over_errors++; set_bit(SLF_ERROR, &sl->flags); } } - sl->mtu = dev->mtu; - + sl->mtu = mtu; + dev->mtu = mtu; sl->buffsize = len; + err = 0; - restore_flags(flags); +done_on_bh: + end_bh_atomic(); - if (oxbuff != NULL) { - kfree(oxbuff); - } - if (orbuff != NULL) { - kfree(orbuff); - } +done: + if (xbuff) + kfree(xbuff); + if (rbuff) + kfree(rbuff); #ifdef SL_INCLUDE_CSLIP - if (ocbuff != NULL) { - kfree(ocbuff); - } + if (cbuff) + kfree(cbuff); #endif + return err; } @@ -398,14 +402,7 @@ unsigned char *p; int actual, count; - - if (sl->mtu != sl->dev->mtu) { /* Someone has been ifconfigging */ - - sl_changedmtu(sl); - } - if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */ - len = sl->mtu; printk ("%s: truncating oversized transmit packet!\n", sl->dev->name); sl->tx_dropped++; sl_unlock(sl); @@ -440,8 +437,10 @@ #endif sl->xleft = count - actual; sl->xhead = sl->xbuff + actual; +#ifdef CONFIG_SLIP_SMART /* VSV */ clear_bit(SLF_OUTWAIT, &sl->flags); /* reset outfill flag */ +#endif } /* @@ -480,8 +479,14 @@ if (!dev->start) { printk("%s: xmit call when iface is down\n", dev->name); - return 1; + dev_kfree_skb(skb); + return 0; + } + if (sl->tty == NULL) { + dev_kfree_skb(skb); + return 0; } + /* * If we are busy already- too bad. We ought to be able * to queue things at this point, to allow for a little @@ -518,113 +523,143 @@ sl_lock(sl); sl->tx_bytes+=skb->len; sl_encaps(sl, skb->data, skb->len); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } return 0; } -/* Return the frame type ID. This is normally IP but maybe be AX.25. */ +/****************************************** + * Routines looking at netdevice side. + ******************************************/ + +/* Netdevice UP -> DOWN routine */ -/* Open the low-level part of the SLIP channel. Easy! */ static int -sl_open(struct device *dev) +sl_close(struct device *dev) { struct slip *sl = (struct slip*)(dev->priv); - unsigned long len; - - if (sl->tty == NULL) { - return -ENODEV; - } - /* - * Allocate the SLIP frame buffers: - * - * rbuff Receive buffer. - * xbuff Transmit buffer. - * cbuff Temporary compression buffer. - */ - len = dev->mtu * 2; - /* - * allow for arrival of larger UDP packets, even if we say not to - * also fixes a bug in which SunOS sends 512-byte packets even with - * an MSS of 128 - */ - if (len < 576 * 2) { - len = 576 * 2; - } - sl->rbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); - if (sl->rbuff == NULL) { - goto norbuff; - } - sl->xbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); - if (sl->xbuff == NULL) { - goto noxbuff; - } -#ifdef SL_INCLUDE_CSLIP - sl->cbuff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); - if (sl->cbuff == NULL) { - goto nocbuff; - } - sl->slcomp = slhc_init(16, 16); - if (sl->slcomp == NULL) { - goto noslcomp; + start_bh_atomic(); + if (sl->tty) { + /* TTY discipline is running. */ + sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); } -#endif - sl->mtu = dev->mtu; - sl->buffsize = len; + dev->tbusy = 1; + dev->start = 0; sl->rcount = 0; sl->xleft = 0; -#ifdef CONFIG_SLIP_MODE_SLIP6 - sl->xdata = 0; - sl->xbits = 0; -#endif - sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */ -#ifdef CONFIG_SLIP_SMART - sl->keepalive=0; /* no keepalive by default = VSV */ - init_timer(&sl->keepalive_timer); /* initialize timer_list struct */ - sl->keepalive_timer.data=(unsigned long)sl; - sl->keepalive_timer.function=sl_keepalive; - sl->outfill=0; /* & outfill too */ - init_timer(&sl->outfill_timer); - sl->outfill_timer.data=(unsigned long)sl; - sl->outfill_timer.function=sl_outfill; -#endif - dev->tbusy = 0; - dev->start = 1; + end_bh_atomic(); + MOD_DEC_USE_COUNT; return 0; +} - /* Cleanup */ +/* Netdevice DOWN -> UP routine */ + +static int sl_open(struct device *dev) +{ + struct slip *sl = (struct slip*)(dev->priv); + + if (sl->tty==NULL) + return -ENODEV; + + sl->flags &= (1 << SLF_INUSE); + dev->start = 1; + dev->tbusy = 0; + MOD_INC_USE_COUNT; + return 0; +} + +/* Netdevice change MTU request */ + +static int sl_change_mtu(struct device *dev, int new_mtu) +{ + struct slip *sl = (struct slip*)(dev->priv); + + if (new_mtu < 68 || new_mtu > 65534) + return -EINVAL; + + if (new_mtu != dev->mtu) + return sl_realloc_bufs(sl, new_mtu); + return 0; +} + +/* Netdevice get statistics request */ + +static struct net_device_stats * +sl_get_stats(struct device *dev) +{ + static struct net_device_stats stats; + struct slip *sl = (struct slip*)(dev->priv); #ifdef SL_INCLUDE_CSLIP -noslcomp: - kfree(sl->cbuff); -nocbuff: + struct slcompress *comp; #endif - kfree(sl->xbuff); -noxbuff: - kfree(sl->rbuff); -norbuff: - return -ENOMEM; + + memset(&stats, 0, sizeof(struct net_device_stats)); + + stats.rx_packets = sl->rx_packets; + stats.tx_packets = sl->tx_packets; + stats.rx_bytes = sl->rx_bytes; + stats.tx_bytes = sl->tx_bytes; + stats.rx_dropped = sl->rx_dropped; + stats.tx_dropped = sl->tx_dropped; + stats.tx_errors = sl->tx_errors; + stats.rx_errors = sl->rx_errors; + stats.rx_over_errors = sl->rx_over_errors; +#ifdef SL_INCLUDE_CSLIP + stats.rx_fifo_errors = sl->rx_compressed; + stats.tx_fifo_errors = sl->tx_compressed; + stats.collisions = sl->tx_misses; + comp = sl->slcomp; + if (comp) { + stats.rx_fifo_errors += comp->sls_i_compressed; + stats.rx_dropped += comp->sls_i_tossed; + stats.tx_fifo_errors += comp->sls_o_compressed; + stats.collisions += comp->sls_o_misses; + } +#endif /* CONFIG_INET */ + return (&stats); } +/* Netdevice register callback */ -/* Close the low-level part of the SLIP channel. Easy! */ -static int -sl_close(struct device *dev) +static int sl_init(struct device *dev) { struct slip *sl = (struct slip*)(dev->priv); - if (sl->tty == NULL) { - return -EBUSY; - } - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - dev->tbusy = 1; - dev->start = 0; + /* + * Finish setting up the DEVICE info. + */ + + dev->mtu = sl->mtu; + dev->hard_start_xmit = sl_xmit; + dev->open = sl_open; + dev->stop = sl_close; + dev->get_stats = sl_get_stats; + dev->change_mtu = sl_change_mtu; +#ifdef CONFIG_SLIP_SMART + dev->do_ioctl = sl_ioctl; +#endif + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->type = ARPHRD_SLIP + sl->mode; + dev->tx_queue_len = 10; + + dev_init_buffers(dev); + + /* New-style flags. */ + dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST; return 0; } + +/****************************************** + Routines looking at TTY side. + ******************************************/ + + static int slip_receive_room(struct tty_struct *tty) { return 65536; /* We can handle an infinite amount of data. :-) */ @@ -644,15 +679,6 @@ if (!sl || sl->magic != SLIP_MAGIC || !sl->dev->start) return; - /* - * Argh! mtu change time! - costs us the packet part received - * at the change - */ - if (sl->mtu != sl->dev->mtu) { - - sl_changedmtu(sl); - } - /* Read the characters out of the buffer */ while (count--) { if (fp && *fp++) { @@ -671,6 +697,127 @@ } } +/************************************ + * slip_open helper routines. + ************************************/ + +/* Collect hanged up channels */ + +static void sl_sync(void) +{ + int i; + + for (i = 0; i < slip_maxdev; i++) { + slip_ctrl_t *slp = slip_ctrls[i]; + if (slp == NULL) + break; + if (slp->ctrl.tty || slp->ctrl.leased) + continue; + if (slp->dev.flags&IFF_UP) + dev_close(&slp->dev); + } +} + +/* Find a free SLIP channel, and link in this `tty' line. */ +static struct slip * +sl_alloc(kdev_t line) +{ + struct slip *sl; + slip_ctrl_t *slp = NULL; + int i; + int sel = -1; + int score = -1; + + if (slip_ctrls == NULL) + return NULL; /* Master array missing ! */ + + for (i = 0; i < slip_maxdev; i++) { + slp = slip_ctrls[i]; + if (slp == NULL) + break; + + if (slp->ctrl.leased) { + if (slp->ctrl.line != line) + continue; + if (slp->ctrl.tty) + return NULL; + + /* Clear ESCAPE & ERROR flags */ + slp->ctrl.flags &= (1 << SLF_INUSE); + return &slp->ctrl; + } + + if (slp->ctrl.tty) + continue; + + if (current->pid == slp->ctrl.pid) { + if (slp->ctrl.line == line && score < 3) { + sel = i; + score = 3; + continue; + } + if (score < 2) { + sel = i; + score = 2; + } + continue; + } + if (slp->ctrl.line == line && score < 1) { + sel = i; + score = 1; + continue; + } + if (score < 0) { + sel = i; + score = 0; + } + } + + if (sel >= 0) { + i = sel; + slp = slip_ctrls[i]; + if (score > 1) { + slp->ctrl.flags &= (1 << SLF_INUSE); + return &slp->ctrl; + } + } + + /* Sorry, too many, all slots in use */ + if (i >= slip_maxdev) + return NULL; + + if (slp) { + if (test_bit(SLF_INUSE, &slp->ctrl.flags)) { + unregister_netdevice(&slp->dev); + sl_free_bufs(&slp->ctrl); + } + } else if ((slp = (slip_ctrl_t *)kmalloc(sizeof(slip_ctrl_t),GFP_KERNEL)) == NULL) + return NULL; + + memset(slp, 0, sizeof(slip_ctrl_t)); + + sl = &slp->ctrl; + /* Initialize channel control data */ + sl->magic = SLIP_MAGIC; + sl->dev = &slp->dev; + sl->mode = SL_MODE_DEFAULT; + sprintf(slp->if_name, "sl%d", i); + slp->dev.name = slp->if_name; + slp->dev.base_addr = i; + slp->dev.priv = (void*)sl; + slp->dev.init = sl_init; +#ifdef CONFIG_SLIP_SMART + init_timer(&sl->keepalive_timer); /* initialize timer_list struct */ + sl->keepalive_timer.data=(unsigned long)sl; + sl->keepalive_timer.function=sl_keepalive; + init_timer(&sl->outfill_timer); + sl->outfill_timer.data=(unsigned long)sl; + sl->outfill_timer.function=sl_outfill; +#endif + slip_ctrls[i] = slp; + return &slp->ctrl; +} + /* * Open the high-level part of the SLIP channel. * This function is called by the TTY module when the @@ -681,42 +828,98 @@ static int slip_open(struct tty_struct *tty) { - struct slip *sl = (struct slip *) tty->disc_data; + struct slip *sl; int err; + MOD_INC_USE_COUNT; + + /* RTnetlink lock is misused here to serialize concurrent + opens of slip channels. There are better ways, but it is + the simplest one. + */ + rtnl_lock(); + + /* Collect hanged up channels. */ + sl_sync(); + + sl = (struct slip *) tty->disc_data; + + err = -EEXIST; /* First make sure we're not already connected. */ - if (sl && sl->magic == SLIP_MAGIC) { - return -EEXIST; - } + if (sl && sl->magic == SLIP_MAGIC) + goto err_exit; /* OK. Find a free SLIP channel to use. */ - if ((sl = sl_alloc()) == NULL) { - return -ENFILE; - } + err = -ENFILE; + if ((sl = sl_alloc(tty->device)) == NULL) + goto err_exit; sl->tty = tty; tty->disc_data = sl; - if (tty->driver.flush_buffer) { + sl->line = tty->device; + sl->pid = current->pid; + 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); - } - /* Restore default settings */ - sl->mode = SL_MODE_DEFAULT; - sl->dev->type = ARPHRD_SLIP + sl->mode; - /* Perform the low-level SLIP initialization. */ - if ((err = sl_open(sl->dev))) { - return err; + if (!test_bit(SLF_INUSE, &sl->flags)) { + /* Perform the low-level SLIP initialization. */ + if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0) + goto err_free_chan; + + if (register_netdevice(sl->dev)) { + sl_free_bufs(sl); + goto err_free_chan; + } + + set_bit(SLF_INUSE, &sl->flags); } - MOD_INC_USE_COUNT; +#ifdef CONFIG_SLIP_SMART + if (sl->keepalive) { + sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; + add_timer (&sl->keepalive_timer); + } + if (sl->outfill) { + sl->outfill_timer.expires=jiffies+sl->outfill*HZ; + add_timer (&sl->outfill_timer); + } +#endif /* Done. We have linked the TTY line to a channel. */ + rtnl_unlock(); return sl->dev->base_addr; + +err_free_chan: + sl->tty = NULL; + tty->disc_data = NULL; + clear_bit(SLF_INUSE, &sl->flags); + +err_exit: + rtnl_unlock(); + + /* Count references from TTY module */ + MOD_DEC_USE_COUNT; + return err; } +/* + Let me to blame a bit. + 1. TTY module calls this funstion on soft interrupt. + 2. TTY module calls this function WITH MASKED INTERRUPTS! + 3. TTY module does not notify us about line discipline + shutdown, + + Seems, now it is clean. The solution is to consider netdevice and + line discipline sides as two independant threads. + + By-product (not desired): sl? does not feel hangups and remains open. + It is supposed, that user level program (dip, diald, slattach...) + will catch SIGHUP and make the rest of work. + + I see no way to make more with current tty code. --ANK + */ /* * Close down a SLIP channel. @@ -730,69 +933,26 @@ struct slip *sl = (struct slip *) tty->disc_data; /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC) { + if (!sl || sl->magic != SLIP_MAGIC || sl->tty != tty) return; - } - - rtnl_lock(); - if (sl->dev->flags & IFF_UP) - { - /* STRONG layering violation! --ANK */ - (void) dev_close(sl->dev); - } tty->disc_data = 0; sl->tty = NULL; + if (!sl->leased) + sl->line = 0; + /* VSV = very important to remove timers */ #ifdef CONFIG_SLIP_SMART if (sl->keepalive) - (void)del_timer (&sl->keepalive_timer); + del_timer (&sl->keepalive_timer); if (sl->outfill) - (void)del_timer (&sl->outfill_timer); + del_timer (&sl->outfill_timer); #endif - sl_free(sl); - unregister_netdevice(sl->dev); - rtnl_unlock(); - MOD_DEC_USE_COUNT; -} - -static struct net_device_stats * -sl_get_stats(struct device *dev) -{ - static struct net_device_stats stats; - struct slip *sl = (struct slip*)(dev->priv); -#ifdef SL_INCLUDE_CSLIP - struct slcompress *comp; -#endif - - memset(&stats, 0, sizeof(struct net_device_stats)); - - stats.rx_packets = sl->rx_packets; - stats.tx_packets = sl->tx_packets; - stats.rx_bytes = sl->rx_bytes; - stats.tx_bytes = sl->tx_bytes; - stats.rx_dropped = sl->rx_dropped; - stats.tx_dropped = sl->tx_dropped; - stats.tx_errors = sl->tx_errors; - stats.rx_errors = sl->rx_errors; - stats.rx_over_errors = sl->rx_over_errors; -#ifdef SL_INCLUDE_CSLIP - stats.rx_fifo_errors = sl->rx_compressed; - stats.tx_fifo_errors = sl->tx_compressed; - stats.collisions = sl->tx_misses; - comp = sl->slcomp; - if (comp) { - stats.rx_fifo_errors += comp->sls_i_compressed; - stats.rx_dropped += comp->sls_i_tossed; - stats.tx_fifo_errors += comp->sls_o_compressed; - stats.collisions += comp->sls_o_misses; - } -#endif /* CONFIG_INET */ - return (&stats); + /* Count references from TTY module */ + MOD_DEC_USE_COUNT; } - /************************************************************************ * STANDARD SLIP ENCAPSULATION * ************************************************************************/ @@ -840,9 +1000,11 @@ switch(s) { case END: +#ifdef CONFIG_SLIP_SMART /* drop keeptest bit = VSV */ if (test_bit(SLF_KEEPTEST, &sl->flags)) clear_bit(SLF_KEEPTEST, &sl->flags); +#endif if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { sl_bump(sl); @@ -925,9 +1087,11 @@ unsigned char c; if (s == 0x70) { +#ifdef CONFIG_SLIP_SMART /* drop keeptest bit = VSV */ if (test_bit(SLF_KEEPTEST, &sl->flags)) clear_bit(SLF_KEEPTEST, &sl->flags); +#endif if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) { sl_bump(sl); @@ -959,7 +1123,6 @@ slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) { struct slip *sl = (struct slip *) tty->disc_data; - int err; unsigned int tmp; /* First make sure we're connected. */ @@ -969,27 +1132,22 @@ switch(cmd) { case SIOCGIFNAME: - err = verify_area(VERIFY_WRITE, arg, strlen(sl->dev->name) + 1); - if (err) { - return err; - } - copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1); + /* Please, do not put this line under copy_to_user, + it breaks my old poor gcc on alpha --ANK + */ + tmp = strlen(sl->dev->name) + 1; + if (copy_to_user(arg, sl->dev->name, tmp)) + return -EFAULT; return 0; case SIOCGIFENCAP: - err = verify_area(VERIFY_WRITE, arg, sizeof(int)); - if (err) { - return err; - } - put_user(sl->mode, (int *)arg); + if (put_user(sl->mode, (int *)arg)) + return -EFAULT; return 0; case SIOCSIFENCAP: - err = verify_area(VERIFY_READ, arg, sizeof(int)); - if (err) { - return err; - } - get_user(tmp,(int *)arg); + if (get_user(tmp,(int *)arg)) + return -EFAULT; #ifndef SL_INCLUDE_CSLIP if (tmp & (SL_MODE_CSLIP|SL_MODE_ADAPTIVE)) { return -EINVAL; @@ -1016,13 +1174,16 @@ #ifdef CONFIG_SLIP_SMART /* VSV changes start here */ case SIOCSKEEPALIVE: - err = verify_area(VERIFY_READ, arg, sizeof(int)); - if (err) { - return -err; - } - get_user(tmp,(int *)arg); + if (get_user(tmp,(int *)arg)) + return -EFAULT; if (tmp > 255) /* max for unchar */ return -EINVAL; + + start_bh_atomic(); + if (!sl->tty) { + end_bh_atomic(); + return -ENODEV; + } if (sl->keepalive) (void)del_timer (&sl->keepalive_timer); if ((sl->keepalive = (unchar) tmp) != 0) { @@ -1030,24 +1191,25 @@ add_timer(&sl->keepalive_timer); set_bit(SLF_KEEPTEST, &sl->flags); } + end_bh_atomic(); + return 0; case SIOCGKEEPALIVE: - err = verify_area(VERIFY_WRITE, arg, sizeof(int)); - if (err) { - return -err; - } - put_user(sl->keepalive, (int *)arg); + if (put_user(sl->keepalive, (int *)arg)) + return -EFAULT; return 0; case SIOCSOUTFILL: - err = verify_area(VERIFY_READ, arg, sizeof(int)); - if (err) { - return -err; - } - get_user(tmp,(int *)arg); + if (get_user(tmp,(int *)arg)) + return -EFAULT; if (tmp > 255) /* max for unchar */ return -EINVAL; + start_bh_atomic(); + if (!sl->tty) { + end_bh_atomic(); + return -ENODEV; + } if (sl->outfill) (void)del_timer (&sl->outfill_timer); if ((sl->outfill = (unchar) tmp) != 0){ @@ -1055,14 +1217,12 @@ add_timer(&sl->outfill_timer); set_bit(SLF_OUTWAIT, &sl->flags); } + end_bh_atomic(); return 0; case SIOCGOUTFILL: - err = verify_area(VERIFY_WRITE, arg, sizeof(int)); - if (err) { - return -err; - } - put_user(sl->outfill, (int *)arg); + if (put_user(sl->outfill, (int *)arg)) + return -EFAULT; return 0; /* VSV changes end */ #endif @@ -1090,6 +1250,13 @@ if (sl == NULL) /* Allocation failed ?? */ return -ENODEV; + start_bh_atomic(); /* Hangup would kill us */ + + if (!sl->tty) { + end_bh_atomic(); + return -ENODEV; + } + switch(cmd){ case SIOCSKEEPALIVE: /* max for unchar */ @@ -1123,20 +1290,30 @@ case SIOCGOUTFILL: rq->ifr_data=(caddr_t)((unsigned long)sl->outfill); + break; + + case SIOCSLEASE: + /* Resolve race condition, when ioctl'ing hanged up + and opened by another process device. + */ + if (sl->tty != current->tty && sl->pid != current->pid) { + end_bh_atomic(); + return -EPERM; + } + sl->leased = 0; + if ((unsigned long)rq->ifr_data) + sl->leased = 1; + break; + + case SIOCGLEASE: + rq->ifr_data=(caddr_t)((unsigned long)sl->leased); }; + end_bh_atomic(); return 0; } #endif /* VSV changes end */ -static int sl_open_dev(struct device *dev) -{ - struct slip *sl = (struct slip*)(dev->priv); - if(sl->tty==NULL) - return -ENODEV; - return 0; -} - /* Initialize SLIP control device -- register SLIP line discipline */ #ifdef MODULE static int slip_init_ctrl_dev(void) @@ -1202,45 +1379,7 @@ } -/* Initialise the SLIP driver. Called by the device init code */ - -int slip_init(struct device *dev) -{ - struct slip *sl = (struct slip*)(dev->priv); - - if (sl == NULL) /* Allocation failed ?? */ - return -ENODEV; - - /* Set up the "SLIP Control Block". (And clear statistics) */ - - memset(sl, 0, sizeof (struct slip)); - sl->magic = SLIP_MAGIC; - sl->dev = dev; - - /* - * Finish setting up the DEVICE info. - */ - - dev->mtu = SL_MTU; - dev->hard_start_xmit = sl_xmit; - dev->open = sl_open_dev; - dev->stop = sl_close; - dev->get_stats = sl_get_stats; -#ifdef CONFIG_SLIP_SMART - dev->do_ioctl = sl_ioctl; -#endif - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = ARPHRD_SLIP + SL_MODE_DEFAULT; - dev->tx_queue_len = 10; - - dev_init_buffers(dev); - - /* New-style flags. */ - dev->flags = IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST; - return 0; -} #ifdef MODULE int @@ -1254,25 +1393,51 @@ { int i; - if (slip_ctrls != NULL) - { - for (i = 0; i < slip_maxdev; i++) - { - if (slip_ctrls[i]) - { - /* - * VSV = if dev->start==0, then device - * unregistered while close proc. - */ - if (slip_ctrls[i]->dev.start) - unregister_netdev(&(slip_ctrls[i]->dev)); + if (slip_ctrls != NULL) { + unsigned long start = jiffies; + int busy = 0; + + /* First of all: check for active disciplines and hangup them. + */ + do { + if (busy) { + current->counter = 0; + schedule(); + } + + busy = 0; + start_bh_atomic(); + for (i = 0; i < slip_maxdev; i++) { + struct slip_ctrl *slc = slip_ctrls[i]; + if (slc && slc->ctrl.tty) { + busy++; + tty_hangup(slc->ctrl.tty); + } + } + end_bh_atomic(); + } while (busy && jiffies - start < 1*HZ); - kfree(slip_ctrls[i]); + busy = 0; + for (i = 0; i < slip_maxdev; i++) { + struct slip_ctrl *slc = slip_ctrls[i]; + if (slc) { + unregister_netdev(&slc->dev); + if (slc->ctrl.tty) { + printk("%s: tty discipline is still running\n", slc->dev.name); + /* Pin module forever */ + MOD_INC_USE_COUNT; + busy++; + continue; + } + sl_free_bufs(&slc->ctrl); + kfree(slc); slip_ctrls[i] = NULL; } } - kfree(slip_ctrls); - slip_ctrls = NULL; + if (!busy) { + kfree(slip_ctrls); + slip_ctrls = NULL; + } } if ((i = tty_register_ldisc(N_SLIP, NULL))) { @@ -1291,7 +1456,7 @@ { struct slip *sl=(struct slip *)sls; - if(sls==0L) + if (sl==NULL || sl->tty == NULL) return; if(sl->outfill) @@ -1317,15 +1482,13 @@ sl->outfill_timer.expires=jiffies+sl->outfill*HZ; add_timer(&sl->outfill_timer); } - else - del_timer(&sl->outfill_timer); } static void sl_keepalive(unsigned long sls) { struct slip *sl=(struct slip *)sls; - if(sl == NULL) + if (sl == NULL || sl->tty == NULL) return; if( sl->keepalive) @@ -1333,7 +1496,6 @@ if(test_bit(SLF_KEEPTEST, &sl->flags)) { /* keepalive still high :(, we must hangup */ - (void)del_timer(&sl->keepalive_timer); if( sl->outfill ) /* outfill timer must be deleted too */ (void)del_timer(&sl->outfill_timer); printk("%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name); @@ -1343,12 +1505,9 @@ } else set_bit(SLF_KEEPTEST, &sl->flags); - (void)del_timer(&sl->keepalive_timer); - sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; + sl->keepalive_timer.expires=jiffies+sl->keepalive*HZ; add_timer(&sl->keepalive_timer); } - else - (void)del_timer(&sl->keepalive_timer); } #endif diff -ur --new-file old/linux/drivers/net/slip.h new/linux/drivers/net/slip.h --- old/linux/drivers/net/slip.h Sun Feb 2 14:18:42 1997 +++ new/linux/drivers/net/slip.h Sun Mar 1 23:40:39 1998 @@ -97,6 +97,9 @@ #define SLF_OUTWAIT 4 /* is outpacket was flag */ unsigned char mode; /* SLIP mode */ + unsigned char leased; + kdev_t line; + pid_t pid; #define SL_MODE_SLIP 0 #define SL_MODE_CSLIP 1 #define SL_MODE_SLIP6 2 /* Matt Dillon's printable slip */ diff -ur --new-file old/linux/drivers/net/smc-mca.c new/linux/drivers/net/smc-mca.c --- old/linux/drivers/net/smc-mca.c Mon Nov 3 18:29:31 1997 +++ new/linux/drivers/net/smc-mca.c Thu Feb 19 23:58:40 1998 @@ -367,10 +367,10 @@ { /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(ioaddr, ULTRA_IO_EXTENT); - unregister_netdev(dev); } } } 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 Sun Jan 4 19:55:08 1998 +++ new/linux/drivers/net/smc-ultra.c Thu Feb 19 23:58:40 1998 @@ -475,10 +475,10 @@ if (dev->priv != NULL) { /* NB: ultra_close_card() does free_irq */ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; release_region(ioaddr, ULTRA_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/smc-ultra32.c new/linux/drivers/net/smc-ultra32.c --- old/linux/drivers/net/smc-ultra32.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/net/smc-ultra32.c Thu Feb 26 20:01:24 1998 @@ -0,0 +1,413 @@ +/* smc-ultra32.c: An SMC Ultra32 EISA ethernet driver for linux. + +Sources: + + This driver is based on (cloned from) the ISA SMC Ultra driver + written by Donald Becker. Modifications to support the EISA + version of the card by Paul Gortmaker and Leonard N. Zubkoff. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + +Theory of Operation: + + The SMC Ultra32C card uses the SMC 83c790 chip which is also + found on the ISA SMC Ultra cards. It has a shared memory mode of + operation that makes it similar to the ISA version of the card. + The main difference is that the EISA card has 32KB of RAM, but + only an 8KB window into that memory. The EISA card also can be + set for a bus-mastering mode of operation via the ECU, but that + is not (and probably will never be) supported by this driver. + The ECU should be run to enable shared memory and to disable the + bus-mastering feature for use with linux. + + By programming the 8390 to use only 8KB RAM, the modifications + to the ISA driver can be limited to the probe and initialization + code. This allows easy integration of EISA support into the ISA + driver. However, the driver development kit from SMC provided the + register information for sliding the 8KB window, and hence the 8390 + is programmed to use the full 32KB RAM. + + Unfortunately this required code changes outside the probe/init + routines, and thus we decided to separate the EISA driver from + the ISA one. In this way, ISA users don't end up with a larger + driver due to the EISA code, and EISA users don't end up with a + larger driver due to the ISA EtherEZ PIO code. The driver is + similar to the 3c503/16 driver, in that the window must be set + back to the 1st 8KB of space for access to the two 8390 Tx slots. + + In testing, using only 8KB RAM (3 Tx / 5 Rx) didn't appear to + be a limiting factor, since the EISA bus could get packets off + the card fast enough, but having the use of lots of RAM as Rx + space is extra insurance if interrupt latencies become excessive. + +*/ + +static const char *version = "smc-ultra32.c: 06/97 v1.00\n"; + + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "8390.h" + +int ultra32_probe(struct device *dev); +int ultra32_probe1(struct device *dev, int ioaddr); +static int ultra32_open(struct device *dev); +static void ultra32_reset_8390(struct device *dev); +static void ultra32_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, + int ring_page); +static void ultra32_block_input(struct device *dev, int count, + struct sk_buff *skb, int ring_offset); +static void ultra32_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page); +static int ultra32_close(struct device *dev); + +#define ULTRA32_CMDREG 0 /* Offset to ASIC command register. */ +#define ULTRA32_RESET 0x80 /* Board reset, in ULTRA32_CMDREG. */ +#define ULTRA32_MEMENB 0x40 /* Enable the shared memory. */ +#define ULTRA32_NIC_OFFSET 16 /* NIC register offset from the base_addr. */ +#define ULTRA32_IO_EXTENT 32 +#define EN0_ERWCNT 0x08 /* Early receive warning count. */ + +/* + * Defines that apply only to the Ultra32 EISA card. Note that + * "smc" = 10011 01101 00011 = 0x4da3, and hence !smc8010.cfg translates + * into an EISA ID of 0x1080A34D + */ +#define ULTRA32_BASE 0xca0 +#define ULTRA32_ID 0x1080a34d +#define ULTRA32_IDPORT (-0x20) /* 0xc80 */ +/* Config regs 1->7 from the EISA !SMC8010.CFG file. */ +#define ULTRA32_CFG1 0x04 /* 0xca4 */ +#define ULTRA32_CFG2 0x05 /* 0xca5 */ +#define ULTRA32_CFG3 (-0x18) /* 0xc88 */ +#define ULTRA32_CFG4 (-0x17) /* 0xc89 */ +#define ULTRA32_CFG5 (-0x16) /* 0xc8a */ +#define ULTRA32_CFG6 (-0x15) /* 0xc8b */ +#define ULTRA32_CFG7 0x0d /* 0xcad */ + + +/* Probe for the Ultra32. This looks like a 8013 with the station + address PROM at I/O ports +8 to +13, with a checksum + following. +*/ + +__initfunc(int ultra32_probe(struct device *dev)) +{ + const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"}; + int ioaddr, edge, media; + + if (!EISA_bus) return ENODEV; + + /* EISA spec allows for up to 16 slots, but 8 is typical. */ + for (ioaddr = 0x1000 + ULTRA32_BASE; ioaddr < 0x9000; ioaddr += 0x1000) + if (check_region(ioaddr, ULTRA32_IO_EXTENT) == 0 && + inb(ioaddr + ULTRA32_IDPORT) != 0xff && + inl(ioaddr + ULTRA32_IDPORT) == ULTRA32_ID) { + media = inb(ioaddr + ULTRA32_CFG7) & 0x03; + edge = inb(ioaddr + ULTRA32_CFG5) & 0x08; + printk("SMC Ultra32 in EISA Slot %d, Media: %s, %s IRQs.\n", + ioaddr >> 12, ifmap[media], + (edge ? "Edge Triggered" : "Level Sensitive")); + if (ultra32_probe1(dev, ioaddr) == 0) + return 0; + } + return ENODEV; +} + +__initfunc(int ultra32_probe1(struct device *dev, int ioaddr)) +{ + int i; + int checksum = 0; + const char *model_name; + static unsigned version_printed = 0; + /* Values from various config regs. */ + unsigned char idreg = inb(ioaddr + 7); + unsigned char reg4 = inb(ioaddr + 4) & 0x7f; + + /* Check the ID nibble. */ + if ((idreg & 0xf0) != 0x20) /* SMC Ultra */ + return ENODEV; + + /* Select the station address register set. */ + outb(reg4, ioaddr + 4); + + for (i = 0; i < 8; i++) + checksum += inb(ioaddr + 8 + i); + if ((checksum & 0xff) != 0xff) + return ENODEV; + + /* We should have a "dev" from Space.c or the static module table. */ + if (dev == NULL) { + printk("smc-ultra32.c: Passed a NULL device.\n"); + dev = init_etherdev(0, 0); + } + + if (ei_debug && version_printed++ == 0) + printk(version); + + model_name = "SMC Ultra32"; + + printk("%s: %s at 0x%X,", dev->name, model_name, ioaddr); + + for (i = 0; i < 6; i++) + printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i)); + + /* Switch from the station address to the alternate register set and + read the useful registers there. */ + outb(0x80 | reg4, ioaddr + 4); + + /* Enable FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */ + outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c); + + /* Reset RAM addr. */ + outb(0x00, ioaddr + 0x0b); + + /* Switch back to the station address register set so that the + MS-DOS driver can find the card after a warm boot. */ + outb(reg4, ioaddr + 4); + + if ((inb(ioaddr + ULTRA32_CFG5) & 0x40) == 0) { + printk("\nsmc-ultra32: Card RAM is disabled! " + "Run EISA config utility.\n"); + return ENODEV; + } + if ((inb(ioaddr + ULTRA32_CFG2) & 0x04) == 0) + printk("\nsmc-ultra32: Ignoring Bus-Master enable bit. " + "Run EISA config utility.\n"); + + if (dev->irq < 2) { + unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15}; + int irq = irqmap[inb(ioaddr + ULTRA32_CFG5) & 0x07]; + if (irq == 0) { + printk(", failed to detect IRQ line.\n"); + return -EAGAIN; + } + dev->irq = irq; + } + + /* Allocate dev->priv and fill in 8390 specific dev fields. */ + if (ethdev_init(dev)) { + printk (", no memory for dev->priv.\n"); + return -ENOMEM; + } + + /* OK, we are certain this is going to work. Setup the device. */ + request_region(ioaddr, ULTRA32_IO_EXTENT, model_name); + + /* The 8390 isn't at the base address, so fake the offset */ + dev->base_addr = ioaddr + ULTRA32_NIC_OFFSET; + + /* Save RAM address in the unused reg0 to avoid excess inb's. */ + ei_status.reg0 = inb(ioaddr + ULTRA32_CFG3) & 0xfc; + + dev->mem_start = 0xc0000 + ((ei_status.reg0 & 0x7c) << 11); + + ei_status.name = model_name; + ei_status.word16 = 1; + ei_status.tx_start_page = 0; + ei_status.rx_start_page = TX_PAGES; + /* All Ultra32 cards have 32KB memory with an 8KB window. */ + ei_status.stop_page = 128; + + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->mem_end = dev->rmem_end = dev->mem_start + 0x1fff; + + printk(", IRQ %d, 32KB memory, 8KB window at 0x%lx-0x%lx.\n", + dev->irq, dev->mem_start, dev->mem_end); + ei_status.block_input = &ultra32_block_input; + ei_status.block_output = &ultra32_block_output; + ei_status.get_8390_hdr = &ultra32_get_8390_hdr; + ei_status.reset_8390 = &ultra32_reset_8390; + dev->open = &ultra32_open; + dev->stop = &ultra32_close; + NS8390_init(dev, 0); + + return 0; +} + +static int ultra32_open(struct device *dev) +{ + int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */ + + if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, dev)) + return -EAGAIN; + + outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */ + outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */ + outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */ + outb(0x01, ioaddr + 6); /* Enable Interrupts. */ + /* Set the early receive warning level in window 0 high enough not + to receive ERW interrupts. */ + outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr); + outb(0xff, dev->base_addr + EN0_ERWCNT); + ei_open(dev); + MOD_INC_USE_COUNT; + return 0; +} + +static int ultra32_close(struct device *dev) +{ + int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */ + + dev->start = 0; + dev->tbusy = 1; + + if (ei_debug > 1) + printk("%s: Shutting down ethercard.\n", dev->name); + + outb(0x00, ioaddr + ULTRA32_CFG6); /* Disable Interrupts. */ + outb(0x00, ioaddr + 6); /* Disable interrupts. */ + free_irq(dev->irq, dev); + + NS8390_init(dev, 0); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static void ultra32_reset_8390(struct device *dev) +{ + int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC base addr */ + + outb(ULTRA32_RESET, ioaddr); + if (ei_debug > 1) printk("resetting Ultra32, t=%ld...", jiffies); + ei_status.txing = 0; + + outb(ULTRA32_MEMENB, ioaddr); /* Enable Shared Memory. */ + outb(0x80, ioaddr + ULTRA32_CFG6); /* Enable Interrupts. */ + outb(0x84, ioaddr + 5); /* Enable MEM16 & Disable Bus Master. */ + outb(0x01, ioaddr + 6); /* Enable Interrupts. */ + if (ei_debug > 1) printk("reset done\n"); + return; +} + +/* Grab the 8390 specific header. Similar to the block_input routine, but + we don't need to be concerned with ring wrap as the header will be at + the start of a page, so we optimize accordingly. */ + +static void ultra32_get_8390_hdr(struct device *dev, + struct e8390_pkt_hdr *hdr, + int ring_page) +{ + unsigned long hdr_start = dev->mem_start + ((ring_page & 0x1f) << 8); + unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3; + + /* Select correct 8KB Window. */ + outb(ei_status.reg0 | ((ring_page & 0x60) >> 5), RamReg); + +#ifdef notdef + /* Officially this is what we are doing, but the readl() is faster */ + memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); +#else + ((unsigned int*)hdr)[0] = readl(hdr_start); +#endif +} + +/* Block input and output are easy on shared memory ethercards, the only + complication is when the ring buffer wraps, or in this case, when a + packet spans an 8KB boundary. Note that the current 8KB segment is + already set by the get_8390_hdr routine. */ + +static void ultra32_block_input(struct device *dev, + int count, + struct sk_buff *skb, + int ring_offset) +{ + unsigned long xfer_start = dev->mem_start + (ring_offset & 0x1fff); + unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3; + + if ((ring_offset & ~0x1fff) != ((ring_offset + count - 1) & ~0x1fff)) { + int semi_count = 8192 - (ring_offset & 0x1FFF); + memcpy_fromio(skb->data, xfer_start, semi_count); + count -= semi_count; + if (ring_offset < 96*256) { + /* Select next 8KB Window. */ + ring_offset += semi_count; + outb(ei_status.reg0 | ((ring_offset & 0x6000) >> 13), RamReg); + memcpy_fromio(skb->data + semi_count, dev->mem_start, count); + } else { + /* Select first 8KB Window. */ + outb(ei_status.reg0, RamReg); + memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); + } + } else { + /* Packet is in one chunk -- we can copy + cksum. */ + eth_io_copy_and_sum(skb, xfer_start, count, 0); + } +} + +static void ultra32_block_output(struct device *dev, + int count, + const unsigned char *buf, + int start_page) +{ + unsigned long xfer_start = dev->mem_start + (start_page<<8); + unsigned int RamReg = dev->base_addr - ULTRA32_NIC_OFFSET + ULTRA32_CFG3; + + /* Select first 8KB Window. */ + outb(ei_status.reg0, RamReg); + + memcpy_toio(xfer_start, buf, count); +} + +#ifdef MODULE +#define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */ +#define NAMELEN 8 /* # of chars for storing dev->name */ +static char namelist[NAMELEN * MAX_ULTRA32_CARDS] = { 0, }; +static struct device dev_ultra[MAX_ULTRA32_CARDS] = { + { + NULL, /* assign a chunk of namelist[] below */ + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL + }, +}; + +int init_module(void) +{ + int this_dev, found = 0; + + for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { + struct device *dev = &dev_ultra[this_dev]; + dev->name = namelist+(NAMELEN*this_dev); + dev->init = ultra32_probe; + if (register_netdev(dev) != 0) { + if (found > 0) return 0; /* Got at least one. */ + printk(KERN_WARNING "smc-ultra32.c: No SMC Ultra32 found.\n"); + return -ENXIO; + } + found++; + } + + return 0; +} + +void cleanup_module(void) +{ + int this_dev; + + for (this_dev = 0; this_dev < MAX_ULTRA32_CARDS; this_dev++) { + struct device *dev = &dev_ultra[this_dev]; + if (dev->priv != NULL) { + /* NB: ultra32_close_card() does free_irq + irq2dev */ + int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; + kfree(dev->priv); + dev->priv = NULL; + release_region(ioaddr, ULTRA32_IO_EXTENT); + unregister_netdev(dev); + } + } +} +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/smc9194.c new/linux/drivers/net/smc9194.c --- old/linux/drivers/net/smc9194.c Mon Nov 3 18:29:31 1997 +++ new/linux/drivers/net/smc9194.c Tue Feb 10 21:56:45 1998 @@ -573,7 +573,7 @@ printk(CARDNAME": Far too big packet error. \n"); /* freeing the packet is a good thing here... but should . any packets of this size get down here? */ - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); lp->saved_skb = NULL; /* this IS an error, but, i don't want the skb saved */ return 0; @@ -725,7 +725,7 @@ PRINTK2((CARDNAME": Sent packet of length %d \n",length)); lp->saved_skb = NULL; - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); dev->trans_start = jiffies; @@ -1246,7 +1246,7 @@ 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 CARDNAME": Transmitter access conflict.\n"); - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); } else { /* Well, I want to send the packet.. but I don't know if I can send it right now... */ diff -ur --new-file old/linux/drivers/net/sonic.c new/linux/drivers/net/sonic.c --- old/linux/drivers/net/sonic.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/net/sonic.c Tue Feb 10 21:56:45 1998 @@ -404,7 +404,7 @@ */ if ((laddr = vdma_alloc(PHYSADDR(skb->data),skb->len)) == ~0UL) { printk("%s: no VDMA entry for transmit available.\n",dev->name); - dev_kfree_skb(skb,FREE_WRITE); + dev_kfree_skb(skb); dev->tbusy = 0; return 1; } @@ -506,7 +506,7 @@ /* We must free the original skb */ if (lp->tx_skb[entry]) { - dev_kfree_skb(lp->tx_skb[entry],FREE_WRITE); + dev_kfree_skb(lp->tx_skb[entry]); lp->tx_skb[entry] = 0; } /* and the VDMA address */ diff -ur --new-file old/linux/drivers/net/strip.c new/linux/drivers/net/strip.c --- old/linux/drivers/net/strip.c Sun Nov 30 23:00:38 1997 +++ new/linux/drivers/net/strip.c Tue Feb 10 21:56:45 1998 @@ -82,7 +82,6 @@ #include #endif -#include #include #include #include @@ -1575,7 +1574,7 @@ strip_send(strip_info, skb); - if (skb) dev_kfree_skb(skb, FREE_WRITE); + if (skb) dev_kfree_skb(skb); return(0); } @@ -1631,11 +1630,9 @@ static int strip_rebuild_header(struct sk_buff *skb) { +#ifdef CONFIG_INET STRIP_Header *header = (STRIP_Header *)skb->data; - /*printk(KERN_INFO "%s: strip_rebuild_header\n", skb->dev->name);*/ - -#ifdef CONFIG_INET /* Arp find returns zero if if knows the address, */ /* or if it doesn't know the address it sends an ARP packet and returns non-zero */ return arp_find(header->dst_addr.c, skb)? 1 : 0; diff -ur --new-file old/linux/drivers/net/sunhme.c new/linux/drivers/net/sunhme.c --- old/linux/drivers/net/sunhme.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/net/sunhme.c Tue Feb 10 21:56:45 1998 @@ -931,14 +931,14 @@ for(i = 0; i < RX_RING_SIZE; i++) { if(hp->rx_skbs[i] != NULL) { - dev_kfree_skb(hp->rx_skbs[i], FREE_READ); + dev_kfree_skb(hp->rx_skbs[i]); hp->rx_skbs[i] = NULL; } } for(i = 0; i < TX_RING_SIZE; i++) { if(hp->tx_skbs[i] != NULL) { - dev_kfree_skb(hp->tx_skbs[i], FREE_WRITE); + dev_kfree_skb(hp->tx_skbs[i]); hp->tx_skbs[i] = NULL; } } @@ -1612,7 +1612,7 @@ mmu_sync_dma(kva_to_hva(hp, skb->data), skb->len, hp->happy_sbus_dev->my_bus); #endif - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); hp->net_stats.tx_packets++; elem = NEXT_TX(elem); @@ -1644,7 +1644,7 @@ hp->tx_skbs[elem] = NULL; hp->net_stats.tx_bytes+=skb->len; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); hp->net_stats.tx_packets++; elem = NEXT_TX(elem); @@ -2330,7 +2330,7 @@ dev->trans_start = jiffies; hp->etxregs->tx_pnding = ETX_TP_DMAWAKEUP; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); if(TX_BUFFS_AVAIL(hp)) dev->tbusy = 0; diff -ur --new-file old/linux/drivers/net/sunlance.c new/linux/drivers/net/sunlance.c --- old/linux/drivers/net/sunlance.c Tue Jan 13 00:28:18 1998 +++ new/linux/drivers/net/sunlance.c Tue Feb 10 21:56:45 1998 @@ -870,7 +870,7 @@ /* Kick the lance: transmit now */ ll->rdp = LE_C0_INEA | LE_C0_TDMD; dev->trans_start = jiffies; - dev_kfree_skb (skb, FREE_WRITE); + dev_kfree_skb (skb); if (TX_BUFFS_AVAIL) dev->tbusy = 0; diff -ur --new-file old/linux/drivers/net/sunqe.c new/linux/drivers/net/sunqe.c --- old/linux/drivers/net/sunqe.c Thu Sep 4 22:25:28 1997 +++ new/linux/drivers/net/sunqe.c Tue Feb 10 21:56:45 1998 @@ -116,14 +116,14 @@ for(i = 0; i < RX_RING_SIZE; i++) { if(qep->rx_skbs[i] != NULL) { - dev_kfree_skb(qep->rx_skbs[i], FREE_READ); + dev_kfree_skb(qep->rx_skbs[i]); qep->rx_skbs[i] = NULL; } } for(i = 0; i < TX_RING_SIZE; i++) { if(qep->tx_skbs[i] != NULL) { - dev_kfree_skb(qep->tx_skbs[i], FREE_WRITE); + dev_kfree_skb(qep->tx_skbs[i]); qep->tx_skbs[i] = NULL; } } @@ -451,7 +451,7 @@ mmu_sync_dma(((u32)((unsigned long)skb->data)), skb->len, qep->qe_sbusdev->my_bus); #endif - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); qep->net_stats.tx_packets++; elem = NEXT_TX(elem); @@ -804,7 +804,7 @@ qep->net_stats.tx_bytes+=skb->len; - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); if(SUN4C_TX_BUFFS_AVAIL(qep)) dev->tbusy = 0; diff -ur --new-file old/linux/drivers/net/tlan.c new/linux/drivers/net/tlan.c --- old/linux/drivers/net/tlan.c Sun Jan 4 19:55:09 1998 +++ new/linux/drivers/net/tlan.c Tue Feb 10 21:56:45 1998 @@ -663,7 +663,7 @@ if ( ! priv->phyOnline ) { TLAN_DBG( TLAN_DEBUG_TX, "TLAN TRANSMIT: %s PHY is not ready\n", dev->name ); - dev_kfree_skb( skb, FREE_WRITE ); + dev_kfree_skb( skb ); return 0; } @@ -710,7 +710,7 @@ if ( priv->txTail >= TLAN_NUM_TX_LISTS ) priv->txTail = 0; - dev_kfree_skb( skb, FREE_WRITE ); + dev_kfree_skb( skb ); dev->trans_start = jiffies; return 0; diff -ur --new-file old/linux/drivers/net/tulip.c new/linux/drivers/net/tulip.c --- old/linux/drivers/net/tulip.c Tue Jan 13 00:28:18 1998 +++ new/linux/drivers/net/tulip.c Mon Mar 16 23:17:29 1998 @@ -636,7 +636,7 @@ for (i = 0; i < 5; i++) dev->dev_addr[i] = last_phys_addr[i]; dev->dev_addr[i] = last_phys_addr[i] + 1; -#if defined(__i386) /* This BIOS bug doesn't exist on Alphas. */ +#if defined(__i386__) /* This BIOS bug doesn't exist on Alphas. */ irq = last_irq; #endif } @@ -1094,17 +1094,13 @@ outl(0x00200000 | 0xE000, ioaddr + CSR0); #elif defined(__powerpc__) outl(0x00200080 | 0x8000, ioaddr + CSR0); -#elif defined(__i386) +#elif defined(__i386__) #if defined(MODULE) /* When a module we don't have 'x86' to check. */ outl(0x00200000 | 0x4800, ioaddr + CSR0); #else #ifndef ORIGINAL_TEXT -#ifndef __SMP__ -#define x86 ((struct cpuinfo_x86*)cpu_data)->x86 -#else -#error What should we make here? -#endif +#define x86 (boot_cpu_data.x86) #endif outl(0x00200000 | (x86 <= 4 ? 0x4800 : 0x8000), ioaddr + CSR0); if (x86 <= 4) @@ -1753,7 +1749,15 @@ #ifdef CONFIG_NET_FASTROUTE cli(); - dev->tx_semaphore = 0; + if (xchg(&dev->tx_semaphore,0) == 0) { + sti(); + /* With new queueing algorithm returning 1 when dev->tbusy == 0 + should not result in lockups, but I am still not sure. --ANK + */ + if (net_ratelimit()) + printk(KERN_CRIT "Please check: are you still alive?\n"); + return 1; + } #endif /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ @@ -1764,7 +1768,7 @@ if (jiffies - dev->trans_start >= TX_TIMEOUT) tulip_tx_timeout(dev); #ifdef CONFIG_NET_FASTROUTE - dev->tx_semaphore = 0; + dev->tx_semaphore = 1; #endif return 1; } @@ -1795,6 +1799,7 @@ if (entry == TX_RING_SIZE-1) flag |= 0xe2000000; + tp->stats.tx_bytes += skb->len; tp->tx_ring[entry].length = skb->len | flag; tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */ tp->cur_tx++; @@ -1803,7 +1808,7 @@ dev->trans_start = jiffies; #ifdef CONFIG_NET_FASTROUTE - dev->tx_semaphore = 0; + dev->tx_semaphore = 1; sti(); #endif @@ -1890,7 +1895,7 @@ } /* Free the original skb. */ - dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE); + dev_kfree_skb(lp->tx_skbuff[entry]); lp->tx_skbuff[entry] = 0; } @@ -2304,12 +2309,12 @@ #if LINUX_VERSION_CODE < 0x20100 skb->free = 1; #endif - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } } for (i = 0; i < TX_RING_SIZE; i++) { if (tp->tx_skbuff[i]) - dev_kfree_skb(tp->tx_skbuff[i], FREE_WRITE); + dev_kfree_skb(tp->tx_skbuff[i]); tp->tx_skbuff[i] = 0; } diff -ur --new-file old/linux/drivers/net/wavelan.c new/linux/drivers/net/wavelan.c --- old/linux/drivers/net/wavelan.c Mon Nov 3 18:29:31 1997 +++ new/linux/drivers/net/wavelan.c Tue Feb 10 21:56:45 1998 @@ -2821,7 +2821,7 @@ wv_packet_write(dev, skb->data, skb->len); } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); #ifdef DEBUG_TX_TRACE printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); diff -ur --new-file old/linux/drivers/net/wd.c new/linux/drivers/net/wd.c --- old/linux/drivers/net/wd.c Sun Jan 4 19:55:09 1998 +++ new/linux/drivers/net/wd.c Thu Feb 19 23:58:40 1998 @@ -497,11 +497,11 @@ struct device *dev = &dev_wd[this_dev]; if (dev->priv != NULL) { int ioaddr = dev->base_addr - WD_NIC_OFFSET; + unregister_netdev(dev); kfree(dev->priv); dev->priv = NULL; free_irq(dev->irq, dev); release_region(ioaddr, WD_IO_EXTENT); - unregister_netdev(dev); } } } diff -ur --new-file old/linux/drivers/net/x25_asy.c new/linux/drivers/net/x25_asy.c --- old/linux/drivers/net/x25_asy.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/net/x25_asy.c Sat Feb 21 03:28:22 1998 @@ -11,7 +11,6 @@ * checksum routines from ppp.c */ -#include #include #include @@ -244,7 +243,7 @@ skb->protocol=htons(ETH_P_X25); if((err=lapb_data_received(sl,skb))!=LAPB_OK) { - kfree_skb(skb, FREE_READ); + kfree_skb(skb); printk(KERN_DEBUG "x25_asy: data received err - %d\n",err); } else @@ -342,13 +341,13 @@ case 0x01: /* Connection request .. do nothing */ if((err=lapb_connect_request(sl))!=LAPB_OK) printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return 0; case 0x02: /* Disconnect request .. do nothing - hang up ?? */ if((err=lapb_disconnect_request(sl))!=LAPB_OK) printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); default: - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return 0; } skb_pull(skb,1); /* Remove control byte */ @@ -385,7 +384,7 @@ if((err=lapb_data_request(sl,skb))!=LAPB_OK) { printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return 0; } return 0; @@ -418,7 +417,7 @@ if(sl->dev->tbusy) { printk(KERN_ERR "x25_asy: tbusy drop\n"); - kfree_skb(skb, FREE_WRITE); + kfree_skb(skb); return; } /* We were not busy, so we are now... :-) */ @@ -427,7 +426,7 @@ x25_asy_lock(sl); sl->tx_bytes+=skb->len; x25_asy_encaps(sl, skb->data, skb->len); - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); } } diff -ur --new-file old/linux/drivers/net/znet.c new/linux/drivers/net/znet.c --- old/linux/drivers/net/znet.c Mon Nov 3 18:29:31 1997 +++ new/linux/drivers/net/znet.c Tue Feb 10 21:56:45 1998 @@ -395,7 +395,7 @@ if (znet_debug > 4) printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length); } - dev_kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb); return 0; } diff -ur --new-file old/linux/drivers/pci/Makefile new/linux/drivers/pci/Makefile --- old/linux/drivers/pci/Makefile Mon Dec 22 02:27:18 1997 +++ new/linux/drivers/pci/Makefile Mon Jan 26 20:43:18 1998 @@ -12,7 +12,14 @@ L_OBJS := pci.o L_TARGET := pci.a -ifeq ($(CONFIG_PCI_OPTIMIZE),y) +ifdef CONFIG_PROC_FS +L_OBJS += proc.o +ifdef CONFIG_PCI_OLD_PROC +L_OBJS += oldproc.o +endif +endif + +ifdef CONFIG_PCI_OPTIMIZE L_OBJS += quirks.o endif diff -ur --new-file old/linux/drivers/pci/oldproc.c new/linux/drivers/pci/oldproc.c --- old/linux/drivers/pci/oldproc.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/pci/oldproc.c Thu Mar 5 00:31:34 1998 @@ -0,0 +1,910 @@ +/* + * $Id: oldproc.c,v 1.4 1998/01/05 14:16:18 mj Exp $ + * + * Backward-compatible procfs interface for PCI. + * + * Copyright 1993, 1994, 1995, 1997 Drew Eckhardt, Frederic Potter, + * David Mosberger-Tang, Martin Mares + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS + +struct pci_dev_info { + unsigned short vendor; /* vendor id */ + unsigned short device; /* device id */ + + const char *name; /* device name */ +}; + +#define DEVICE(vid,did,name) \ + {PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##did, (name)} + +/* + * Sorted in ascending order by vendor and device. + * Use binary search for lookup. If you add a device make sure + * it is sequential by both vendor and device id. + */ +struct pci_dev_info dev_info[] = { + DEVICE( COMPAQ, COMPAQ_1280, "QVision 1280/p"), + DEVICE( COMPAQ, COMPAQ_SMART2P, "Smart-2/P RAID Controller"), + DEVICE( COMPAQ, COMPAQ_NETEL100,"Netelligent 10/100"), + DEVICE( COMPAQ, COMPAQ_NETEL10, "Netelligent 10"), + DEVICE( COMPAQ, COMPAQ_NETFLEX3I,"NetFlex 3"), + DEVICE( COMPAQ, COMPAQ_NETEL100D,"Netelligent 10/100 Dual"), + DEVICE( COMPAQ, COMPAQ_NETEL100PI,"Netelligent 10/100 ProLiant"), + DEVICE( COMPAQ, COMPAQ_NETEL100I,"Netelligent 10/100 Integrated"), + DEVICE( COMPAQ, COMPAQ_THUNDER, "ThunderLAN"), + DEVICE( COMPAQ, COMPAQ_NETFLEX3B,"NetFlex 3 BNC"), + DEVICE( NCR, NCR_53C810, "53c810"), + DEVICE( NCR, NCR_53C820, "53c820"), + DEVICE( NCR, NCR_53C825, "53c825"), + DEVICE( NCR, NCR_53C815, "53c815"), + DEVICE( NCR, NCR_53C860, "53c860"), + DEVICE( NCR, NCR_53C896, "53c896"), + DEVICE( NCR, NCR_53C895, "53c895"), + DEVICE( NCR, NCR_53C885, "53c885"), + DEVICE( NCR, NCR_53C875, "53c875"), + DEVICE( NCR, NCR_53C875J, "53c875J"), + DEVICE( ATI, ATI_68800, "68800AX"), + DEVICE( ATI, ATI_215CT222, "215CT222"), + DEVICE( ATI, ATI_210888CX, "210888CX"), + DEVICE( ATI, ATI_215GB, "Mach64 GB"), + DEVICE( ATI, ATI_215GD, "Mach64 GD (Rage Pro)"), + DEVICE( ATI, ATI_215GP, "Mach64 GP (Rage Pro)"), + DEVICE( ATI, ATI_215GT, "Mach64 GT (Rage II)"), + DEVICE( ATI, ATI_215GTB, "Mach64 GT (Rage II)"), + DEVICE( ATI, ATI_210888GX, "210888GX"), + DEVICE( ATI, ATI_264VT, "Mach64 VT"), + DEVICE( VLSI, VLSI_82C592, "82C592-FC1"), + DEVICE( VLSI, VLSI_82C593, "82C593-FC1"), + DEVICE( VLSI, VLSI_82C594, "82C594-AFC2"), + DEVICE( VLSI, VLSI_82C597, "82C597-AFC2"), + DEVICE( VLSI, VLSI_82C541, "82C541 Lynx"), + DEVICE( VLSI, VLSI_82C543, "82C543 Lynx ISA"), + DEVICE( VLSI, VLSI_82C532, "82C532"), + DEVICE( VLSI, VLSI_82C534, "82C534"), + DEVICE( VLSI, VLSI_82C535, "82C535"), + DEVICE( VLSI, VLSI_82C147, "82C147"), + DEVICE( VLSI, VLSI_VAS96011, "VAS96011 (Golden Gate II)"), + DEVICE( ADL, ADL_2301, "2301"), + DEVICE( NS, NS_87415, "87415"), + DEVICE( NS, NS_87410, "87410"), + DEVICE( TSENG, TSENG_W32P_2, "ET4000W32P"), + DEVICE( TSENG, TSENG_W32P_b, "ET4000W32P rev B"), + DEVICE( TSENG, TSENG_W32P_c, "ET4000W32P rev C"), + DEVICE( TSENG, TSENG_W32P_d, "ET4000W32P rev D"), + DEVICE( TSENG, TSENG_ET6000, "ET6000"), + DEVICE( WEITEK, WEITEK_P9000, "P9000"), + DEVICE( WEITEK, WEITEK_P9100, "P9100"), + DEVICE( DEC, DEC_BRD, "DC21050"), + DEVICE( DEC, DEC_TULIP, "DC21040"), + DEVICE( DEC, DEC_TGA, "TGA"), + DEVICE( DEC, DEC_TULIP_FAST, "DC21140"), + DEVICE( DEC, DEC_TGA2, "TGA2"), + DEVICE( DEC, DEC_FDDI, "DEFPA"), + DEVICE( DEC, DEC_TULIP_PLUS, "DC21041"), + DEVICE( DEC, DEC_21142, "DC21142"), + DEVICE( DEC, DEC_21052, "DC21052"), + DEVICE( DEC, DEC_21150, "DC21150"), + DEVICE( DEC, DEC_21152, "DC21152"), + DEVICE( CIRRUS, CIRRUS_7548, "GD 7548"), + DEVICE( CIRRUS, CIRRUS_5430, "GD 5430"), + DEVICE( CIRRUS, CIRRUS_5434_4, "GD 5434"), + DEVICE( CIRRUS, CIRRUS_5434_8, "GD 5434"), + DEVICE( CIRRUS, CIRRUS_5436, "GD 5436"), + DEVICE( CIRRUS, CIRRUS_5446, "GD 5446"), + DEVICE( CIRRUS, CIRRUS_5480, "GD 5480"), + DEVICE( CIRRUS, CIRRUS_5464, "GD 5464"), + DEVICE( CIRRUS, CIRRUS_5465, "GD 5465"), + DEVICE( CIRRUS, CIRRUS_6729, "CL 6729"), + DEVICE( CIRRUS, CIRRUS_6832, "PD 6832"), + DEVICE( CIRRUS, CIRRUS_7542, "CL 7542"), + DEVICE( CIRRUS, CIRRUS_7543, "CL 7543"), + DEVICE( CIRRUS, CIRRUS_7541, "CL 7541"), + DEVICE( IBM, IBM_FIRE_CORAL, "Fire Coral"), + DEVICE( IBM, IBM_TR, "Token Ring"), + DEVICE( IBM, IBM_82G2675, "82G2675"), + DEVICE( IBM, IBM_MCA, "MicroChannel"), + DEVICE( IBM, IBM_82351, "82351"), + DEVICE( WD, WD_7197, "WD 7197"), + DEVICE( AMD, AMD_LANCE, "79C970"), + DEVICE( AMD, AMD_SCSI, "53C974"), + DEVICE( TRIDENT, TRIDENT_9397, "Cyber9397"), + DEVICE( TRIDENT, TRIDENT_9420, "TG 9420"), + DEVICE( TRIDENT, TRIDENT_9440, "TG 9440"), + DEVICE( TRIDENT, TRIDENT_9660, "TG 9660 / Cyber9385"), + DEVICE( TRIDENT, TRIDENT_9750, "Image 975"), + DEVICE( AI, AI_M1435, "M1435"), + DEVICE( MATROX, MATROX_MGA_2, "Atlas PX2085"), + DEVICE( MATROX, MATROX_MIL, "Millennium"), + DEVICE( MATROX, MATROX_MYS, "Mystique"), + DEVICE( MATROX, MATROX_MIL_2, "Millennium II"), + DEVICE( MATROX, MATROX_MIL_2_AGP,"Millennium II AGP"), + DEVICE( MATROX, MATROX_MGA_IMP, "MGA Impression"), + DEVICE( CT, CT_65545, "65545"), + DEVICE( CT, CT_65548, "65548"), + DEVICE( CT, CT_65550, "65550"), + DEVICE( CT, CT_65554, "65554"), + DEVICE( MIRO, MIRO_36050, "ZR36050"), + DEVICE( NEC, NEC_PCX2, "PowerVR PCX2"), + DEVICE( FD, FD_36C70, "TMC-18C30"), + DEVICE( SI, SI_6201, "6201"), + DEVICE( SI, SI_6202, "6202"), + DEVICE( SI, SI_503, "85C503"), + DEVICE( SI, SI_6205, "6205"), + DEVICE( SI, SI_501, "85C501"), + DEVICE( SI, SI_496, "85C496"), + DEVICE( SI, SI_601, "85C601"), + DEVICE( SI, SI_5107, "5107"), + DEVICE( SI, SI_5511, "85C5511"), + DEVICE( SI, SI_5513, "85C5513"), + DEVICE( SI, SI_5571, "5571"), + DEVICE( SI, SI_5597, "5597"), + DEVICE( SI, SI_7001, "7001"), + DEVICE( HP, HP_J2585A, "J2585A"), + DEVICE( HP, HP_J2585B, "J2585B (Lassen)"), + DEVICE( PCTECH, PCTECH_RZ1000, "RZ1000 (buggy)"), + DEVICE( PCTECH, PCTECH_RZ1001, "RZ1001 (buggy?)"), + DEVICE( PCTECH, PCTECH_SAMURAI_0,"Samurai 0"), + DEVICE( PCTECH, PCTECH_SAMURAI_1,"Samurai 1"), + DEVICE( PCTECH, PCTECH_SAMURAI_IDE,"Samurai IDE"), + DEVICE( DPT, DPT, "SmartCache/Raid"), + DEVICE( OPTI, OPTI_92C178, "92C178"), + DEVICE( OPTI, OPTI_82C557, "82C557 Viper-M"), + DEVICE( OPTI, OPTI_82C558, "82C558 Viper-M ISA+IDE"), + DEVICE( OPTI, OPTI_82C621, "82C621"), + DEVICE( OPTI, OPTI_82C700, "82C700"), + DEVICE( OPTI, OPTI_82C701, "82C701 FireStar Plus"), + DEVICE( OPTI, OPTI_82C814, "82C814 Firebridge 1"), + DEVICE( OPTI, OPTI_82C822, "82C822"), + DEVICE( OPTI, OPTI_82C825, "82C825 Firebridge 2"), + DEVICE( SGS, SGS_2000, "STG 2000X"), + DEVICE( SGS, SGS_1764, "STG 1764X"), + DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER_NC, "MultiMaster NC"), + DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER, "MultiMaster"), + DEVICE( BUSLOGIC, BUSLOGIC_FLASHPOINT, "FlashPoint"), + DEVICE( TI, TI_TVP4010, "TVP4010 Permedia"), + DEVICE( TI, TI_TVP4020, "TVP4020 Permedia 2"), + DEVICE( TI, TI_PCI1130, "PCI1130"), + DEVICE( TI, TI_PCI1131, "PCI1131"), + DEVICE( TI, TI_PCI1250, "PCI1250"), + DEVICE( OAK, OAK_OTI107, "OTI107"), + DEVICE( WINBOND2, WINBOND2_89C940,"NE2000-PCI"), + DEVICE( MOTOROLA, MOTOROLA_MPC105,"MPC105 Eagle"), + DEVICE( MOTOROLA, MOTOROLA_MPC106,"MPC106 Grackle"), + DEVICE( MOTOROLA, MOTOROLA_RAVEN, "Raven"), + DEVICE( PROMISE, PROMISE_20246, "IDE UltraDMA/33"), + DEVICE( PROMISE, PROMISE_5300, "DC5030"), + DEVICE( N9, N9_I128, "Imagine 128"), + DEVICE( N9, N9_I128_2, "Imagine 128v2"), + DEVICE( UMC, UMC_UM8673F, "UM8673F"), + DEVICE( UMC, UMC_UM8891A, "UM8891A"), + DEVICE( UMC, UMC_UM8886BF, "UM8886BF"), + DEVICE( UMC, UMC_UM8886A, "UM8886A"), + DEVICE( UMC, UMC_UM8881F, "UM8881F"), + DEVICE( UMC, UMC_UM8886F, "UM8886F"), + DEVICE( UMC, UMC_UM9017F, "UM9017F"), + DEVICE( UMC, UMC_UM8886N, "UM8886N"), + DEVICE( UMC, UMC_UM8891N, "UM8891N"), + DEVICE( X, X_AGX016, "ITT AGX016"), + DEVICE( PICOP, PICOP_PT86C52X, "PT86C52x Vesuvius"), + DEVICE( APPLE, APPLE_BANDIT, "Bandit"), + DEVICE( APPLE, APPLE_GC, "Grand Central"), + DEVICE( APPLE, APPLE_HYDRA, "Hydra"), + DEVICE( NEXGEN, NEXGEN_82C501, "82C501"), + DEVICE( QLOGIC, QLOGIC_ISP1020, "ISP1020"), + DEVICE( QLOGIC, QLOGIC_ISP1022, "ISP1022"), + DEVICE( CYRIX, CYRIX_5510, "5510"), + DEVICE( CYRIX, CYRIX_PCI_MASTER,"PCI Master"), + DEVICE( CYRIX, CYRIX_5520, "5520"), + DEVICE( CYRIX, CYRIX_5530_LEGACY,"5530 Kahlua Legacy"), + DEVICE( CYRIX, CYRIX_5530_SMI, "5530 Kahlua SMI"), + DEVICE( CYRIX, CYRIX_5530_IDE, "5530 Kahlua IDE"), + DEVICE( CYRIX, CYRIX_5530_AUDIO,"5530 Kahlua Audio"), + DEVICE( CYRIX, CYRIX_5530_VIDEO,"5530 Kahlua Video"), + DEVICE( LEADTEK, LEADTEK_805, "S3 805"), + DEVICE( CONTAQ, CONTAQ_82C599, "82C599"), + DEVICE( OLICOM, OLICOM_OC3136, "OC-3136/3137"), + DEVICE( OLICOM, OLICOM_OC2315, "OC-2315"), + DEVICE( OLICOM, OLICOM_OC2325, "OC-2325"), + DEVICE( OLICOM, OLICOM_OC2183, "OC-2183/2185"), + DEVICE( OLICOM, OLICOM_OC2326, "OC-2326"), + DEVICE( OLICOM, OLICOM_OC6151, "OC-6151/6152"), + DEVICE( SUN, SUN_EBUS, "EBUS"), + DEVICE( SUN, SUN_HAPPYMEAL, "Happy Meal"), + DEVICE( SUN, SUN_PBM, "PCI Bus Module"), + DEVICE( CMD, CMD_640, "640 (buggy)"), + DEVICE( CMD, CMD_643, "643"), + DEVICE( CMD, CMD_646, "646"), + DEVICE( CMD, CMD_670, "670"), + DEVICE( VISION, VISION_QD8500, "QD-8500"), + DEVICE( VISION, VISION_QD8580, "QD-8580"), + DEVICE( BROOKTREE, BROOKTREE_848, "Bt848"), + DEVICE( BROOKTREE, BROOKTREE_849A, "Bt849"), + DEVICE( BROOKTREE, BROOKTREE_8474, "Bt8474"), + DEVICE( SIERRA, SIERRA_STB, "STB Horizon 64"), + DEVICE( ACC, ACC_2056, "2056"), + DEVICE( WINBOND, WINBOND_83769, "W83769F"), + DEVICE( WINBOND, WINBOND_82C105, "SL82C105"), + DEVICE( WINBOND, WINBOND_83C553, "W83C553"), + DEVICE( DATABOOK, DATABOOK_87144, "DB87144"), + DEVICE( PLX, PLX_9080, "PCI9080 I2O"), + DEVICE( 3COM, 3COM_3C590, "3C590 10bT"), + DEVICE( 3COM, 3COM_3C595TX, "3C595 100bTX"), + DEVICE( 3COM, 3COM_3C595T4, "3C595 100bT4"), + DEVICE( 3COM, 3COM_3C595MII, "3C595 100b-MII"), + DEVICE( 3COM, 3COM_3C900TPO, "3C900 10bTPO"), + DEVICE( 3COM, 3COM_3C900COMBO,"3C900 10b Combo"), + DEVICE( 3COM, 3COM_3C905TX, "3C905 100bTX"), + DEVICE( SMC, SMC_EPIC100, "9432 TX"), + DEVICE( AL, AL_M1445, "M1445"), + DEVICE( AL, AL_M1449, "M1449"), + DEVICE( AL, AL_M1451, "M1451"), + DEVICE( AL, AL_M1461, "M1461"), + DEVICE( AL, AL_M1489, "M1489"), + DEVICE( AL, AL_M1511, "M1511"), + DEVICE( AL, AL_M1513, "M1513"), + DEVICE( AL, AL_M1521, "M1521"), + DEVICE( AL, AL_M1523, "M1523"), + DEVICE( AL, AL_M1531, "M1531 Aladdin IV"), + DEVICE( AL, AL_M1533, "M1533 Aladdin IV"), + DEVICE( AL, AL_M3307, "M3307 MPEG-1 decoder"), + DEVICE( AL, AL_M4803, "M4803"), + DEVICE( AL, AL_M5219, "M5219"), + DEVICE( AL, AL_M5229, "M5229 TXpro"), + DEVICE( AL, AL_M5237, "M5237 USB"), + DEVICE( SURECOM, SURECOM_NE34, "NE-34PCI LAN"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2070, "Magicgraph NM2070"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV"), + DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"), + DEVICE( ASP, ASP_ABP940, "ABP940"), + DEVICE( ASP, ASP_ABP940U, "ABP940U"), + DEVICE( ASP, ASP_ABP940UW, "ABP940UW"), + DEVICE( CERN, CERN_SPSB_PMC, "STAR/RD24 SCI-PCI (PMC)"), + DEVICE( CERN, CERN_SPSB_PCI, "STAR/RD24 SCI-PCI (PMC)"), + DEVICE( IMS, IMS_8849, "8849"), + DEVICE( TEKRAM2, TEKRAM2_690c, "DC690c"), + DEVICE( TUNDRA, TUNDRA_CA91C042,"CA91C042 Universe"), + DEVICE( AMCC, AMCC_MYRINET, "Myrinet PCI (M2-PCI-32)"), + DEVICE( AMCC, AMCC_S5933, "S5933 PCI44"), + DEVICE( AMCC, AMCC_S5933_HEPC3,"S5933 Traquair HEPC3"), + DEVICE( INTERG, INTERG_1680, "IGA-1680"), + DEVICE( INTERG, INTERG_1682, "IGA-1682"), + DEVICE( REALTEK, REALTEK_8029, "8029"), + DEVICE( REALTEK, REALTEK_8129, "8129"), + DEVICE( TRUEVISION, TRUEVISION_T1000,"TARGA 1000"), + DEVICE( INIT, INIT_320P, "320 P"), + DEVICE( INIT, INIT_360P, "360 P"), + DEVICE( VIA, VIA_82C505, "VT 82C505"), + DEVICE( VIA, VIA_82C561, "VT 82C561"), + DEVICE( VIA, VIA_82C586_1, "VT 82C586 Apollo IDE"), + DEVICE( VIA, VIA_82C576, "VT 82C576 3V"), + DEVICE( VIA, VIA_82C585, "VT 82C585 Apollo VP1/VPX"), + DEVICE( VIA, VIA_82C586_0, "VT 82C586 Apollo ISA"), + DEVICE( VIA, VIA_82C595, "VT 82C595 Apollo VP2"), + DEVICE( VIA, VIA_82C597_0, "VT 82C597 Apollo VP3"), + DEVICE( VIA, VIA_82C926, "VT 82C926 Amazon"), + DEVICE( VIA, VIA_82C416, "VT 82C416MV"), + DEVICE( VIA, VIA_82C595_97, "VT 82C595 Apollo VP2/97"), + DEVICE( VIA, VIA_82C586_2, "VT 82C586 Apollo USB"), + DEVICE( VIA, VIA_82C586_3, "VT 82C586B Apollo ACPI"), + DEVICE( VIA, VIA_82C597_1, "VT 82C597 Apollo VP3 AGP"), + DEVICE( VORTEX, VORTEX_GDT60x0, "GDT 60x0"), + DEVICE( VORTEX, VORTEX_GDT6000B,"GDT 6000b"), + DEVICE( VORTEX, VORTEX_GDT6x10, "GDT 6110/6510"), + DEVICE( VORTEX, VORTEX_GDT6x20, "GDT 6120/6520"), + DEVICE( VORTEX, VORTEX_GDT6530, "GDT 6530"), + DEVICE( VORTEX, VORTEX_GDT6550, "GDT 6550"), + DEVICE( VORTEX, VORTEX_GDT6x17, "GDT 6117/6517"), + DEVICE( VORTEX, VORTEX_GDT6x27, "GDT 6127/6527"), + DEVICE( VORTEX, VORTEX_GDT6537, "GDT 6537"), + DEVICE( VORTEX, VORTEX_GDT6557, "GDT 6557"), + DEVICE( VORTEX, VORTEX_GDT6x15, "GDT 6115/6515"), + DEVICE( VORTEX, VORTEX_GDT6x25, "GDT 6125/6525"), + DEVICE( VORTEX, VORTEX_GDT6535, "GDT 6535"), + DEVICE( VORTEX, VORTEX_GDT6555, "GDT 6555"), + DEVICE( VORTEX, VORTEX_GDT6x17RP,"GDT 6117RP/6517RP"), + DEVICE( VORTEX, VORTEX_GDT6x27RP,"GDT 6127RP/6527RP"), + DEVICE( VORTEX, VORTEX_GDT6537RP,"GDT 6537RP"), + DEVICE( VORTEX, VORTEX_GDT6557RP,"GDT 6557RP"), + DEVICE( VORTEX, VORTEX_GDT6x11RP,"GDT 6111RP/6511RP"), + DEVICE( VORTEX, VORTEX_GDT6x21RP,"GDT 6121RP/6521RP"), + DEVICE( VORTEX, VORTEX_GDT6x17RP1,"GDT 6117RP1/6517RP1"), + DEVICE( VORTEX, VORTEX_GDT6x27RP1,"GDT 6127RP1/6527RP1"), + DEVICE( VORTEX, VORTEX_GDT6537RP1,"GDT 6537RP1"), + DEVICE( VORTEX, VORTEX_GDT6557RP1,"GDT 6557RP1"), + DEVICE( VORTEX, VORTEX_GDT6x11RP1,"GDT 6111RP1/6511RP1"), + DEVICE( VORTEX, VORTEX_GDT6x21RP1,"GDT 6121RP1/6521RP1"), + DEVICE( VORTEX, VORTEX_GDT6x17RP2,"GDT 6117RP2/6517RP2"), + DEVICE( VORTEX, VORTEX_GDT6x27RP2,"GDT 6127RP2/6527RP2"), + DEVICE( VORTEX, VORTEX_GDT6537RP2,"GDT 6537RP2"), + DEVICE( VORTEX, VORTEX_GDT6557RP2,"GDT 6557RP2"), + DEVICE( VORTEX, VORTEX_GDT6x11RP2,"GDT 6111RP2/6511RP2"), + DEVICE( VORTEX, VORTEX_GDT6x21RP2,"GDT 6121RP2/6521RP2"), + DEVICE( EF, EF_ATM_FPGA, "155P-MF1 (FPGA)"), + DEVICE( EF, EF_ATM_ASIC, "155P-MF1 (ASIC)"), + DEVICE( FORE, FORE_PCA200PC, "PCA-200PC"), + DEVICE( FORE, FORE_PCA200E, "PCA-200E"), + DEVICE( IMAGINGTECH, IMAGINGTECH_ICPCI, "MVC IC-PCI"), + DEVICE( PHILIPS, PHILIPS_SAA7146,"SAA7146"), + DEVICE( CYCLONE, CYCLONE_SDK, "SDK"), + DEVICE( ALLIANCE, ALLIANCE_PROMOTIO, "Promotion-6410"), + DEVICE( ALLIANCE, ALLIANCE_PROVIDEO, "Provideo"), + DEVICE( ALLIANCE, ALLIANCE_AT24, "AT24"), + DEVICE( ALLIANCE, ALLIANCE_AT3D, "AT3D"), + DEVICE( VMIC, VMIC_VME, "VMIVME-7587"), + DEVICE( DIGI, DIGI_EPC, "AccelPort EPC"), + DEVICE( DIGI, DIGI_RIGHTSWITCH, "RightSwitch SE-6"), + DEVICE( DIGI, DIGI_XEM, "AccelPort Xem"), + DEVICE( DIGI, DIGI_XR, "AccelPort Xr"), + DEVICE( DIGI, DIGI_CX, "AccelPort C/X"), + DEVICE( DIGI, DIGI_XRJ, "AccelPort Xr/J"), + DEVICE( DIGI, DIGI_EPCJ, "AccelPort EPC/J"), + DEVICE( MUTECH, MUTECH_MV1000, "MV-1000"), + DEVICE( RENDITION, RENDITION_VERITE,"Verite 1000"), + DEVICE( RENDITION, RENDITION_VERITE2100,"Verite 2100"), + DEVICE( TOSHIBA, TOSHIBA_601, "Laptop"), + DEVICE( TOSHIBA, TOSHIBA_TOPIC95,"ToPIC95"), + DEVICE( TOSHIBA, TOSHIBA_TOPIC97,"ToPIC97"), + DEVICE( RICOH, RICOH_RL5C466, "RL5C466"), + DEVICE( ARTOP, ARTOP_ATP850UF, "ATP850UF"), + DEVICE( ZEITNET, ZEITNET_1221, "1221"), + DEVICE( ZEITNET, ZEITNET_1225, "1225"), + DEVICE( OMEGA, OMEGA_82C092G, "82C092G"), + DEVICE( LITEON, LITEON_LNE100TX,"LNE100TX"), + DEVICE( NP, NP_PCI_FDDI, "NP-PCI"), + DEVICE( ATT, ATT_L56XMF, "L56xMF"), + DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"), + DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"), + DEVICE( AURAVISION, AURAVISION_VXP524,"VXP524"), + DEVICE( IKON, IKON_10115, "10115 Greensheet"), + DEVICE( IKON, IKON_10117, "10117 Greensheet"), + DEVICE( ZORAN, ZORAN_36057, "ZR36057"), + DEVICE( ZORAN, ZORAN_36120, "ZR36120"), + DEVICE( COMPEX, COMPEX_ENET100VG4, "Readylink ENET100-VG4"), + DEVICE( COMPEX, COMPEX_RL2000, "ReadyLink 2000"), + DEVICE( RP, RP8OCTA, "RocketPort 8 Oct"), + DEVICE( RP, RP8INTF, "RocketPort 8 Intf"), + DEVICE( RP, RP16INTF, "RocketPort 16 Intf"), + DEVICE( RP, RP32INTF, "RocketPort 32 Intf"), + 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( O2, O2_6832, "6832"), + DEVICE( 3DFX, 3DFX_VOODOO, "Voodoo"), + DEVICE( 3DFX, 3DFX_VOODOO2, "Voodoo2"), + DEVICE( SIGMADES, SIGMADES_6425, "REALmagic64/GX"), + DEVICE( STALLION, STALLION_ECHPCI832,"EasyConnection 8/32"), + DEVICE( STALLION, STALLION_ECHPCI864,"EasyConnection 8/64"), + DEVICE( STALLION, STALLION_EIOPCI,"EasyIO"), + DEVICE( OPTIBASE, OPTIBASE_FORGE, "MPEG Forge"), + DEVICE( OPTIBASE, OPTIBASE_FUSION,"MPEG Fusion"), + DEVICE( OPTIBASE, OPTIBASE_VPLEX, "VideoPlex"), + DEVICE( OPTIBASE, OPTIBASE_VPLEXCC,"VideoPlex CC"), + DEVICE( OPTIBASE, OPTIBASE_VQUEST,"VideoQuest"), + DEVICE( ENSONIQ, ENSONIQ_AUDIOPCI,"AudioPCI"), + DEVICE( PICTUREL, PICTUREL_PCIVST,"PCIVST"), + DEVICE( NVIDIA_SGS, NVIDIA_SGS_RIVA128, "Riva 128"), + DEVICE( SYMPHONY, SYMPHONY_101, "82C101"), + DEVICE( TEKRAM, TEKRAM_DC290, "DC-290"), + DEVICE( 3DLABS, 3DLABS_300SX, "GLINT 300SX"), + DEVICE( 3DLABS, 3DLABS_500TX, "GLINT 500TX"), + DEVICE( 3DLABS, 3DLABS_DELTA, "GLINT Delta"), + DEVICE( 3DLABS, 3DLABS_PERMEDIA,"PERMEDIA"), + DEVICE( AVANCE, AVANCE_ALG2064, "ALG2064i"), + DEVICE( AVANCE, AVANCE_2302, "ALG-2302"), + DEVICE( NETVIN, NETVIN_NV5000SC,"NV5000"), + DEVICE( S3, S3_PLATO_PXS, "PLATO/PX (system)"), + DEVICE( S3, S3_ViRGE, "ViRGE"), + DEVICE( S3, S3_TRIO, "Trio32/Trio64"), + DEVICE( S3, S3_AURORA64VP, "Aurora64V+"), + DEVICE( S3, S3_TRIO64UVP, "Trio64UV+"), + DEVICE( S3, S3_ViRGE_VX, "ViRGE/VX"), + DEVICE( S3, S3_868, "Vision 868"), + DEVICE( S3, S3_928, "Vision 928-P"), + DEVICE( S3, S3_864_1, "Vision 864-P"), + DEVICE( S3, S3_864_2, "Vision 864-P"), + DEVICE( S3, S3_964_1, "Vision 964-P"), + DEVICE( S3, S3_964_2, "Vision 964-P"), + DEVICE( S3, S3_968, "Vision 968"), + DEVICE( S3, S3_TRIO64V2, "Trio64V2/DX or /GX"), + DEVICE( S3, S3_PLATO_PXG, "PLATO/PX (graphics)"), + DEVICE( S3, S3_ViRGE_DXGX, "ViRGE/DX or /GX"), + DEVICE( S3, S3_ViRGE_GX2, "ViRGE/GX2"), + DEVICE( S3, S3_ViRGE_MX, "ViRGE/MX"), + DEVICE( S3, S3_ViRGE_MXP, "ViRGE/MX+"), + DEVICE( S3, S3_ViRGE_MXPMV, "ViRGE/MX+MV"), + DEVICE( S3, S3_SONICVIBES, "SonicVibes"), + DEVICE( INTEL, INTEL_82375, "82375EB"), + DEVICE( INTEL, INTEL_82424, "82424ZX Saturn"), + DEVICE( INTEL, INTEL_82378, "82378IB"), + DEVICE( INTEL, INTEL_82430, "82430ZX Aries"), + DEVICE( INTEL, INTEL_82434, "82434LX Mercury/Neptune"), + DEVICE( INTEL, INTEL_82092AA_0,"82092AA PCMCIA bridge"), + DEVICE( INTEL, INTEL_82092AA_1,"82092AA EIDE"), + DEVICE( INTEL, INTEL_7116, "SAA7116"), + DEVICE( INTEL, INTEL_82596, "82596"), + DEVICE( INTEL, INTEL_82865, "82865"), + DEVICE( INTEL, INTEL_82557, "82557"), + DEVICE( INTEL, INTEL_82437, "82437"), + DEVICE( INTEL, INTEL_82371FB_0,"82371FB PIIX ISA"), + DEVICE( INTEL, INTEL_82371FB_1,"82371FB PIIX IDE"), + DEVICE( INTEL, INTEL_82371MX, "430MX - 82371MX MPIIX"), + DEVICE( INTEL, INTEL_82437MX, "430MX - 82437MX MTSC"), + DEVICE( INTEL, INTEL_82441, "82441FX Natoma"), + DEVICE( INTEL, INTEL_82439, "82439HX Triton II"), + DEVICE( INTEL, INTEL_82371SB_0,"82371SB PIIX3 ISA"), + DEVICE( INTEL, INTEL_82371SB_1,"82371SB PIIX3 IDE"), + DEVICE( INTEL, INTEL_82371SB_2,"82371SB PIIX3 USB"), + DEVICE( INTEL, INTEL_82437VX, "82437VX Triton II"), + DEVICE( INTEL, INTEL_82439TX, "82439TX"), + DEVICE( INTEL, INTEL_82371AB_0,"82371AB PIIX4 ISA"), + DEVICE( INTEL, INTEL_82371AB, "82371AB PIIX4 IDE"), + DEVICE( INTEL, INTEL_82371AB_2,"82371AB PIIX4 USB"), + DEVICE( INTEL, INTEL_82371AB_3,"82371AB PIIX4 ACPI"), + DEVICE( INTEL, INTEL_82443LX_0,"440LX - 82443LX PAC Host"), + DEVICE( INTEL, INTEL_82443LX_1,"440LX - 82443LX PAC AGP"), + DEVICE( INTEL, INTEL_P6, "Orion P6"), + DEVICE( INTEL, INTEL_82450GX, "82450GX Orion P6"), + DEVICE( KTI, KTI_ET32P2, "ET32P2"), + DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"), + DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"), + DEVICE( ADAPTEC, ADAPTEC_5800, "AIC-5800"), + DEVICE( ADAPTEC, ADAPTEC_7860, "AIC-7860"), + DEVICE( ADAPTEC, ADAPTEC_7861, "AIC-7861"), + DEVICE( ADAPTEC, ADAPTEC_7870, "AIC-7870"), + DEVICE( ADAPTEC, ADAPTEC_7871, "AIC-7871"), + DEVICE( ADAPTEC, ADAPTEC_7872, "AIC-7872"), + DEVICE( ADAPTEC, ADAPTEC_7873, "AIC-7873"), + DEVICE( ADAPTEC, ADAPTEC_7874, "AIC-7874"), + DEVICE( ADAPTEC, ADAPTEC_7895, "AIC-7895U"), + DEVICE( ADAPTEC, ADAPTEC_7880, "AIC-7880U"), + DEVICE( ADAPTEC, ADAPTEC_7881, "AIC-7881U"), + DEVICE( ADAPTEC, ADAPTEC_7882, "AIC-7882U"), + DEVICE( ADAPTEC, ADAPTEC_7883, "AIC-7883U"), + DEVICE( ADAPTEC, ADAPTEC_7884, "AIC-7884U"), + DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL"), + DEVICE( ARK, ARK_STING, "Stingray"), + DEVICE( ARK, ARK_STINGARK, "Stingray ARK 2000PV"), + DEVICE( ARK, ARK_2000MT, "2000MT") +}; + + +/* + * device_info[] is sorted so we can use binary search + */ +static struct pci_dev_info *pci_lookup_dev(unsigned int vendor, unsigned int dev) +{ + int min = 0, + max = sizeof(dev_info)/sizeof(dev_info[0]) - 1; + + for ( ; ; ) + { + int i = (min + max) >> 1; + long order; + + order = dev_info[i].vendor - (long) vendor; + if (!order) + order = dev_info[i].device - (long) dev; + + if (order < 0) + { + min = i + 1; + if ( min > max ) + return 0; + continue; + } + + if (order > 0) + { + max = i - 1; + if ( min > max ) + return 0; + continue; + } + + return & dev_info[ i ]; + } +} + +static const char *pci_strclass (unsigned int class) +{ + switch (class >> 8) { + case PCI_CLASS_NOT_DEFINED: return "Non-VGA device"; + case PCI_CLASS_NOT_DEFINED_VGA: return "VGA compatible device"; + + case PCI_CLASS_STORAGE_SCSI: return "SCSI storage controller"; + case PCI_CLASS_STORAGE_IDE: return "IDE interface"; + case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller"; + case PCI_CLASS_STORAGE_IPI: return "IPI bus controller"; + case PCI_CLASS_STORAGE_RAID: return "RAID bus controller"; + case PCI_CLASS_STORAGE_OTHER: return "Unknown mass storage controller"; + + case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet controller"; + case PCI_CLASS_NETWORK_TOKEN_RING: return "Token ring network controller"; + case PCI_CLASS_NETWORK_FDDI: return "FDDI network controller"; + case PCI_CLASS_NETWORK_ATM: return "ATM network controller"; + case PCI_CLASS_NETWORK_OTHER: return "Network controller"; + + case PCI_CLASS_DISPLAY_VGA: return "VGA compatible controller"; + case PCI_CLASS_DISPLAY_XGA: return "XGA compatible controller"; + case PCI_CLASS_DISPLAY_OTHER: return "Display controller"; + + case PCI_CLASS_MULTIMEDIA_VIDEO: return "Multimedia video controller"; + case PCI_CLASS_MULTIMEDIA_AUDIO: return "Multimedia audio controller"; + case PCI_CLASS_MULTIMEDIA_OTHER: return "Multimedia controller"; + + case PCI_CLASS_MEMORY_RAM: return "RAM memory"; + case PCI_CLASS_MEMORY_FLASH: return "FLASH memory"; + case PCI_CLASS_MEMORY_OTHER: return "Memory"; + + case PCI_CLASS_BRIDGE_HOST: return "Host bridge"; + case PCI_CLASS_BRIDGE_ISA: return "ISA bridge"; + case PCI_CLASS_BRIDGE_EISA: return "EISA bridge"; + case PCI_CLASS_BRIDGE_MC: return "MicroChannel bridge"; + case PCI_CLASS_BRIDGE_PCI: return "PCI bridge"; + case PCI_CLASS_BRIDGE_PCMCIA: return "PCMCIA bridge"; + case PCI_CLASS_BRIDGE_NUBUS: return "NuBus bridge"; + case PCI_CLASS_BRIDGE_CARDBUS: return "CardBus bridge"; + case PCI_CLASS_BRIDGE_OTHER: return "Bridge"; + + case PCI_CLASS_COMMUNICATION_SERIAL: return "Serial controller"; + case PCI_CLASS_COMMUNICATION_PARALLEL: return "Parallel controller"; + case PCI_CLASS_COMMUNICATION_OTHER: return "Communication controller"; + + case PCI_CLASS_SYSTEM_PIC: return "PIC"; + case PCI_CLASS_SYSTEM_DMA: return "DMA controller"; + case PCI_CLASS_SYSTEM_TIMER: return "Timer"; + case PCI_CLASS_SYSTEM_RTC: return "RTC"; + case PCI_CLASS_SYSTEM_OTHER: return "System peripheral"; + + case PCI_CLASS_INPUT_KEYBOARD: return "Keyboard controller"; + case PCI_CLASS_INPUT_PEN: return "Digitizer Pen"; + case PCI_CLASS_INPUT_MOUSE: return "Mouse controller"; + case PCI_CLASS_INPUT_OTHER: return "Input device controller"; + + case PCI_CLASS_DOCKING_GENERIC: return "Generic Docking Station"; + case PCI_CLASS_DOCKING_OTHER: return "Docking Station"; + + case PCI_CLASS_PROCESSOR_386: return "386"; + case PCI_CLASS_PROCESSOR_486: return "486"; + case PCI_CLASS_PROCESSOR_PENTIUM: return "Pentium"; + case PCI_CLASS_PROCESSOR_ALPHA: return "Alpha"; + case PCI_CLASS_PROCESSOR_POWERPC: return "Power PC"; + case PCI_CLASS_PROCESSOR_CO: return "Co-processor"; + + case PCI_CLASS_SERIAL_FIREWIRE: return "FireWire (IEEE 1394)"; + case PCI_CLASS_SERIAL_ACCESS: return "ACCESS Bus"; + case PCI_CLASS_SERIAL_SSA: return "SSA"; + case PCI_CLASS_SERIAL_USB: return "USB Controller"; + case PCI_CLASS_SERIAL_FIBER: return "Fiber Channel"; + + default: return "Unknown class"; + } +} + + +static const char *pci_strvendor(unsigned int vendor) +{ + switch (vendor) { + case PCI_VENDOR_ID_COMPAQ: return "Compaq"; + case PCI_VENDOR_ID_NCR: return "NCR"; + case PCI_VENDOR_ID_ATI: return "ATI"; + case PCI_VENDOR_ID_VLSI: return "VLSI"; + case PCI_VENDOR_ID_ADL: return "Avance Logic"; + case PCI_VENDOR_ID_NS: return "NS"; + case PCI_VENDOR_ID_TSENG: return "Tseng'Lab"; + case PCI_VENDOR_ID_WEITEK: return "Weitek"; + case PCI_VENDOR_ID_DEC: return "DEC"; + case PCI_VENDOR_ID_CIRRUS: return "Cirrus Logic"; + case PCI_VENDOR_ID_IBM: return "IBM"; + case PCI_VENDOR_ID_WD: return "Western Digital"; + case PCI_VENDOR_ID_AMD: return "AMD"; + case PCI_VENDOR_ID_TRIDENT: return "Trident"; + case PCI_VENDOR_ID_AI: return "Acer Incorporated"; + case PCI_VENDOR_ID_MATROX: return "Matrox"; + case PCI_VENDOR_ID_CT: return "Chips & Technologies"; + case PCI_VENDOR_ID_MIRO: return "Miro"; + case PCI_VENDOR_ID_NEC: return "NEC"; + case PCI_VENDOR_ID_FD: return "Future Domain"; + case PCI_VENDOR_ID_SI: return "Silicon Integrated Systems"; + case PCI_VENDOR_ID_HP: return "Hewlett Packard"; + case PCI_VENDOR_ID_PCTECH: return "PCTECH"; + case PCI_VENDOR_ID_DPT: return "DPT"; + case PCI_VENDOR_ID_OPTI: return "OPTi"; + case PCI_VENDOR_ID_SGS: return "SGS Thomson"; + case PCI_VENDOR_ID_BUSLOGIC: return "BusLogic"; + case PCI_VENDOR_ID_TI: return "Texas Instruments"; + case PCI_VENDOR_ID_OAK: return "OAK"; + case PCI_VENDOR_ID_WINBOND2: return "Winbond"; + case PCI_VENDOR_ID_MOTOROLA: return "Motorola"; + case PCI_VENDOR_ID_PROMISE: return "Promise Technology"; + case PCI_VENDOR_ID_N9: return "Number Nine"; + case PCI_VENDOR_ID_UMC: return "UMC"; + case PCI_VENDOR_ID_X: return "X TECHNOLOGY"; + case PCI_VENDOR_ID_PICOP: return "PicoPower"; + case PCI_VENDOR_ID_APPLE: return "Apple"; + case PCI_VENDOR_ID_NEXGEN: return "Nexgen"; + case PCI_VENDOR_ID_QLOGIC: return "Q Logic"; + case PCI_VENDOR_ID_CYRIX: return "Cyrix"; + case PCI_VENDOR_ID_LEADTEK: return "Leadtek Research"; + case PCI_VENDOR_ID_CONTAQ: return "Contaq"; + case PCI_VENDOR_ID_FOREX: return "Forex"; + case PCI_VENDOR_ID_OLICOM: return "Olicom"; + case PCI_VENDOR_ID_SUN: return "Sun Microsystems"; + case PCI_VENDOR_ID_CMD: return "CMD"; + case PCI_VENDOR_ID_VISION: return "Vision"; + case PCI_VENDOR_ID_BROOKTREE: return "Brooktree"; + case PCI_VENDOR_ID_SIERRA: return "Sierra"; + case PCI_VENDOR_ID_ACC: return "ACC MICROELECTRONICS"; + case PCI_VENDOR_ID_WINBOND: return "Winbond"; + case PCI_VENDOR_ID_DATABOOK: return "Databook"; + case PCI_VENDOR_ID_PLX: return "PLX"; + case PCI_VENDOR_ID_3COM: return "3Com"; + case PCI_VENDOR_ID_SMC: return "SMC"; + case PCI_VENDOR_ID_AL: return "Acer Labs"; + case PCI_VENDOR_ID_MITSUBISHI: return "Mitsubishi"; + case PCI_VENDOR_ID_SURECOM: return "Surecom"; + case PCI_VENDOR_ID_NEOMAGIC: return "Neomagic"; + case PCI_VENDOR_ID_ASP: return "Advanced System Products"; + case PCI_VENDOR_ID_CERN: return "CERN"; + case PCI_VENDOR_ID_NVIDIA: return "NVidia"; + case PCI_VENDOR_ID_IMS: return "IMS"; + case PCI_VENDOR_ID_TEKRAM2: return "Tekram"; + case PCI_VENDOR_ID_TUNDRA: return "Tundra"; + case PCI_VENDOR_ID_AMCC: return "AMCC"; + case PCI_VENDOR_ID_INTERG: return "Intergraphics"; + case PCI_VENDOR_ID_REALTEK: return "Realtek"; + case PCI_VENDOR_ID_TRUEVISION: return "Truevision"; + case PCI_VENDOR_ID_INIT: return "Initio Corp"; + case PCI_VENDOR_ID_VIA: return "VIA Technologies"; + case PCI_VENDOR_ID_VORTEX: return "VORTEX"; + case PCI_VENDOR_ID_EF: return "Efficient Networks"; + case PCI_VENDOR_ID_FORE: return "Fore Systems"; + case PCI_VENDOR_ID_IMAGINGTECH: return "Imaging Technology"; + case PCI_VENDOR_ID_PHILIPS: return "Philips"; + case PCI_VENDOR_ID_CYCLONE: return "Cyclone"; + case PCI_VENDOR_ID_ALLIANCE: return "Alliance"; + case PCI_VENDOR_ID_VMIC: return "VMIC"; + case PCI_VENDOR_ID_DIGI: return "Digi Intl."; + case PCI_VENDOR_ID_MUTECH: return "Mutech"; + case PCI_VENDOR_ID_RENDITION: return "Rendition"; + case PCI_VENDOR_ID_TOSHIBA: return "Toshiba"; + case PCI_VENDOR_ID_RICOH: return "Ricoh"; + case PCI_VENDOR_ID_ARTOP: return "Artop Electronics"; + case PCI_VENDOR_ID_ZEITNET: return "ZeitNet"; + case PCI_VENDOR_ID_OMEGA: return "Omega Micro"; + case PCI_VENDOR_ID_LITEON: return "LiteOn"; + case PCI_VENDOR_ID_NP: return "Network Peripherals"; + case PCI_VENDOR_ID_ATT: return "Lucent (ex-AT&T) Microelectronics"; + case PCI_VENDOR_ID_SPECIALIX: return "Specialix"; + case PCI_VENDOR_ID_AURAVISION: return "Auravision"; + case PCI_VENDOR_ID_IKON: return "Ikon"; + case PCI_VENDOR_ID_ZORAN: return "Zoran"; + case PCI_VENDOR_ID_COMPEX: return "Compex"; + case PCI_VENDOR_ID_RP: return "Comtrol"; + case PCI_VENDOR_ID_CYCLADES: return "Cyclades"; + case PCI_VENDOR_ID_O2: return "O2 Micro"; + case PCI_VENDOR_ID_3DFX: return "3Dfx"; + case PCI_VENDOR_ID_STALLION: return "Stallion Technologies"; + case PCI_VENDOR_ID_SIGMADES: return "Sigma Designs"; + case PCI_VENDOR_ID_OPTIBASE: return "Optibase"; + case PCI_VENDOR_ID_ENSONIQ: return "Ensoniq"; + case PCI_VENDOR_ID_PICTUREL: return "Picture Elements"; + case PCI_VENDOR_ID_NVIDIA_SGS: return "NVidia/SGS Thomson"; + case PCI_VENDOR_ID_SYMPHONY: return "Symphony"; + case PCI_VENDOR_ID_TEKRAM: return "Tekram"; + case PCI_VENDOR_ID_3DLABS: return "3Dlabs"; + case PCI_VENDOR_ID_AVANCE: return "Avance"; + case PCI_VENDOR_ID_NETVIN: return "NetVin"; + case PCI_VENDOR_ID_S3: return "S3 Inc."; + case PCI_VENDOR_ID_INTEL: return "Intel"; + case PCI_VENDOR_ID_KTI: return "KTI"; + case PCI_VENDOR_ID_ADAPTEC: return "Adaptec"; + case PCI_VENDOR_ID_ATRONICS: return "Atronics"; + case PCI_VENDOR_ID_ARK: return "ARK Logic"; + default: return "Unknown vendor"; + } +} + + +static const char *pci_strdev(unsigned int vendor, unsigned int device) +{ + struct pci_dev_info *info; + + info = pci_lookup_dev(vendor, device); + return info ? info->name : "Unknown device"; +} + + +/* + * Convert some of the configuration space registers of the device at + * address (bus,devfn) into a string (possibly several lines each). + * The configuration string is stored starting at buf[len]. If the + * string would exceed the size of the buffer (SIZE), 0 is returned. + */ +static int sprint_dev_config(struct pci_dev *dev, char *buf, int size) +{ + unsigned long base; + unsigned int l, class_rev, bus, devfn; + unsigned short vendor, device, status; + unsigned char bist, latency, min_gnt, max_lat; + int reg, len = 0; + const char *str; + + bus = dev->bus->number; + devfn = dev->devfn; + + pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev); + pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device); + pcibios_read_config_word (bus, devfn, PCI_STATUS, &status); + pcibios_read_config_byte (bus, devfn, PCI_BIST, &bist); + pcibios_read_config_byte (bus, devfn, PCI_LATENCY_TIMER, &latency); + pcibios_read_config_byte (bus, devfn, PCI_MIN_GNT, &min_gnt); + pcibios_read_config_byte (bus, devfn, PCI_MAX_LAT, &max_lat); + if (len + 80 > size) { + return -1; + } + len += sprintf(buf + len, " Bus %2d, device %3d, function %2d:\n", + bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + if (len + 80 > size) { + return -1; + } + len += sprintf(buf + len, " %s: %s %s (rev %d).\n ", + pci_strclass(class_rev >> 8), pci_strvendor(vendor), + pci_strdev(vendor, device), class_rev & 0xff); + + if (!pci_lookup_dev(vendor, device)) { + len += sprintf(buf + len, + "Vendor id=%x. Device id=%x.\n ", + vendor, device); + } + + str = 0; /* to keep gcc shut... */ + switch (status & PCI_STATUS_DEVSEL_MASK) { + case PCI_STATUS_DEVSEL_FAST: str = "Fast devsel. "; break; + case PCI_STATUS_DEVSEL_MEDIUM: str = "Medium devsel. "; break; + case PCI_STATUS_DEVSEL_SLOW: str = "Slow devsel. "; break; + } + if (len + strlen(str) > size) { + return -1; + } + len += sprintf(buf + len, str); + + if (status & PCI_STATUS_FAST_BACK) { +# define fast_b2b_capable "Fast back-to-back capable. " + if (len + strlen(fast_b2b_capable) > size) { + return -1; + } + len += sprintf(buf + len, fast_b2b_capable); +# undef fast_b2b_capable + } + + if (bist & PCI_BIST_CAPABLE) { +# define BIST_capable "BIST capable. " + if (len + strlen(BIST_capable) > size) { + return -1; + } + len += sprintf(buf + len, BIST_capable); +# undef BIST_capable + } + + if (dev->irq) { + if (len + 40 > size) { + return -1; + } + len += sprintf(buf + len, "IRQ %x. ", dev->irq); + } + + if (dev->master) { + if (len + 80 > size) { + return -1; + } + len += sprintf(buf + len, "Master Capable. "); + if (latency) + len += sprintf(buf + len, "Latency=%d. ", latency); + else + len += sprintf(buf + len, "No bursts. "); + if (min_gnt) + len += sprintf(buf + len, "Min Gnt=%d.", min_gnt); + if (max_lat) + len += sprintf(buf + len, "Max Lat=%d.", max_lat); + } + + for (reg = 0; reg < 6; reg++) { + if (len + 40 > size) { + return -1; + } + pcibios_read_config_dword(bus, devfn, + PCI_BASE_ADDRESS_0 + (reg << 2), &l); + if (l == 0xffffffff) + base = 0; + else + base = l; + if (!base) + continue; + + if (base & PCI_BASE_ADDRESS_SPACE_IO) { + len += sprintf(buf + len, + "\n I/O at 0x%lx [0x%lx].", + base & PCI_BASE_ADDRESS_IO_MASK, + dev->base_address[reg]); + } else { + const char *pref, *type = "unknown"; + + if (base & PCI_BASE_ADDRESS_MEM_PREFETCH) { + pref = "P"; + } else { + pref = "Non-p"; + } + switch (base & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + type = "32 bit"; break; + case PCI_BASE_ADDRESS_MEM_TYPE_1M: + type = "20 bit"; break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: + type = "64 bit"; + /* read top 32 bit address of base addr: */ + reg += 4; + pcibios_read_config_dword(bus, devfn, reg, &l); + base |= ((u64) l) << 32; + break; + } + len += sprintf(buf + len, + "\n %srefetchable %s memory at " + "0x%lx [0x%lx].", pref, type, + base & PCI_BASE_ADDRESS_MEM_MASK, + dev->base_address[reg]); + } + } + + len += sprintf(buf + len, "\n"); + return len; +} + + +/* + * Return list of PCI devices as a character string for /proc/pci. + * BUF is a buffer that is PAGE_SIZE bytes long. + */ +int get_pci_list(char *buf) +{ + int nprinted, len, size; + struct pci_dev *dev; + static int complained = 0; +# define MSG "\nwarning: page-size limit reached!\n" + + if (!complained) { + complained++; + printk(KERN_INFO "%s uses obsolete /proc/pci interface\n", + current->comm); + } + + /* reserve same for truncation warning message: */ + size = PAGE_SIZE - (strlen(MSG) + 1); + len = sprintf(buf, "PCI devices found:\n"); + + for (dev = pci_devices; dev; dev = dev->next) { + nprinted = sprint_dev_config(dev, buf + len, size - len); + if (nprinted < 0) { + return len + sprintf(buf + len, MSG); + } + len += nprinted; + } + return len; +} + +#endif /* CONFIG_PROC_FS */ diff -ur --new-file old/linux/drivers/pci/pci.c new/linux/drivers/pci/pci.c --- old/linux/drivers/pci/pci.c Tue Dec 23 23:37:32 1997 +++ new/linux/drivers/pci/pci.c Mon Jan 26 20:43:18 1998 @@ -1,13 +1,13 @@ /* - * $Id: pci.c,v 1.51 1997/12/03 06:18:11 davem Exp $ + * $Id: pci.c,v 1.55 1997/12/27 12:17:54 mj Exp $ * - * PCI services that are built on top of the BIOS32 service. + * PCI services that are built on top of the BIOS32 service. * - * Copyright 1993, 1994, 1995, 1997 Drew Eckhardt, Frederic Potter, + * Copyright 1993, 1994, 1995, 1997 Drew Eckhardt, Frederic Potter, * David Mosberger-Tang, Martin Mares */ + #include -#include #include #include #include @@ -22,667 +22,18 @@ #undef DEBUG -#define DEVICE(vid,did,name) \ - {PCI_VENDOR_ID_##vid, PCI_DEVICE_ID_##did, (name)} - /* - * Sorted in ascending order by vendor and device. - * Use binary search for lookup. If you add a device make sure - * it is sequential by both vendor and device id. - */ -struct pci_dev_info dev_info[] = { - DEVICE( COMPAQ, COMPAQ_1280, "QVision 1280/p"), - DEVICE( COMPAQ, COMPAQ_SMART2P, "Smart-2/P RAID Controller"), - DEVICE( COMPAQ, COMPAQ_NETEL100,"Netelligent 10/100"), - DEVICE( COMPAQ, COMPAQ_NETEL10, "Netelligent 10"), - DEVICE( COMPAQ, COMPAQ_NETFLEX3I,"NetFlex 3"), - DEVICE( COMPAQ, COMPAQ_NETEL100D,"Netelligent 10/100 Dual"), - DEVICE( COMPAQ, COMPAQ_NETEL100PI,"Netelligent 10/100 ProLiant"), - DEVICE( COMPAQ, COMPAQ_NETEL100I,"Netelligent 10/100 Integrated"), - DEVICE( COMPAQ, COMPAQ_THUNDER, "ThunderLAN"), - DEVICE( COMPAQ, COMPAQ_NETFLEX3B,"NetFlex 3 BNC"), - DEVICE( NCR, NCR_53C810, "53c810"), - DEVICE( NCR, NCR_53C820, "53c820"), - DEVICE( NCR, NCR_53C825, "53c825"), - DEVICE( NCR, NCR_53C815, "53c815"), - DEVICE( NCR, NCR_53C860, "53c860"), - DEVICE( NCR, NCR_53C896, "53c896"), - DEVICE( NCR, NCR_53C895, "53c895"), - DEVICE( NCR, NCR_53C885, "53c885"), - DEVICE( NCR, NCR_53C875, "53c875"), - DEVICE( NCR, NCR_53C875J, "53c875J"), - DEVICE( ATI, ATI_68800, "68800AX"), - DEVICE( ATI, ATI_215CT222, "215CT222"), - DEVICE( ATI, ATI_210888CX, "210888CX"), - DEVICE( ATI, ATI_215GB, "Mach64 GB"), - DEVICE( ATI, ATI_215GD, "Mach64 GD (Rage Pro)"), - DEVICE( ATI, ATI_215GP, "Mach64 GP (Rage Pro)"), - DEVICE( ATI, ATI_215GT, "Mach64 GT (Rage II)"), - DEVICE( ATI, ATI_215GTB, "Mach64 GT (Rage II)"), - DEVICE( ATI, ATI_210888GX, "210888GX"), - DEVICE( ATI, ATI_264VT, "Mach64 VT"), - DEVICE( VLSI, VLSI_82C592, "82C592-FC1"), - DEVICE( VLSI, VLSI_82C593, "82C593-FC1"), - DEVICE( VLSI, VLSI_82C594, "82C594-AFC2"), - DEVICE( VLSI, VLSI_82C597, "82C597-AFC2"), - DEVICE( VLSI, VLSI_82C541, "82C541 Lynx"), - DEVICE( VLSI, VLSI_82C543, "82C543 Lynx ISA"), - DEVICE( VLSI, VLSI_VAS96011, "VAS96011 (Golden Gate II)"), - DEVICE( ADL, ADL_2301, "2301"), - DEVICE( NS, NS_87415, "87415"), - DEVICE( NS, NS_87410, "87410"), - DEVICE( TSENG, TSENG_W32P_2, "ET4000W32P"), - DEVICE( TSENG, TSENG_W32P_b, "ET4000W32P rev B"), - DEVICE( TSENG, TSENG_W32P_c, "ET4000W32P rev C"), - DEVICE( TSENG, TSENG_W32P_d, "ET4000W32P rev D"), - DEVICE( TSENG, TSENG_ET6000, "ET6000"), - DEVICE( WEITEK, WEITEK_P9000, "P9000"), - DEVICE( WEITEK, WEITEK_P9100, "P9100"), - DEVICE( DEC, DEC_BRD, "DC21050"), - DEVICE( DEC, DEC_TULIP, "DC21040"), - DEVICE( DEC, DEC_TGA, "TGA"), - DEVICE( DEC, DEC_TULIP_FAST, "DC21140"), - DEVICE( DEC, DEC_TGA2, "TGA2"), - DEVICE( DEC, DEC_FDDI, "DEFPA"), - DEVICE( DEC, DEC_TULIP_PLUS, "DC21041"), - DEVICE( DEC, DEC_21142, "DC21142"), - DEVICE( DEC, DEC_21052, "DC21052"), - DEVICE( DEC, DEC_21152, "DC21152"), - DEVICE( CIRRUS, CIRRUS_7548, "GD 7548"), - DEVICE( CIRRUS, CIRRUS_5430, "GD 5430"), - DEVICE( CIRRUS, CIRRUS_5434_4, "GD 5434"), - DEVICE( CIRRUS, CIRRUS_5434_8, "GD 5434"), - DEVICE( CIRRUS, CIRRUS_5436, "GD 5436"), - DEVICE( CIRRUS, CIRRUS_5446, "GD 5446"), - DEVICE( CIRRUS, CIRRUS_5480, "GD 5480"), - DEVICE( CIRRUS, CIRRUS_5464, "GD 5464"), - DEVICE( CIRRUS, CIRRUS_5465, "GD 5465"), - DEVICE( CIRRUS, CIRRUS_6729, "CL 6729"), - DEVICE( CIRRUS, CIRRUS_6832, "PD 6832"), - DEVICE( CIRRUS, CIRRUS_7542, "CL 7542"), - DEVICE( CIRRUS, CIRRUS_7543, "CL 7543"), - DEVICE( CIRRUS, CIRRUS_7541, "CL 7541"), - DEVICE( IBM, IBM_FIRE_CORAL, "Fire Coral"), - DEVICE( IBM, IBM_TR, "Token Ring"), - DEVICE( IBM, IBM_82G2675, "82G2675"), - DEVICE( IBM, IBM_82351, "82351"), - DEVICE( WD, WD_7197, "WD 7197"), - DEVICE( AMD, AMD_LANCE, "79C970"), - DEVICE( AMD, AMD_SCSI, "53C974"), - DEVICE( TRIDENT, TRIDENT_9420, "TG 9420"), - DEVICE( TRIDENT, TRIDENT_9440, "TG 9440"), - DEVICE( TRIDENT, TRIDENT_9660, "TG 9660 / Cyber9385"), - DEVICE( TRIDENT, TRIDENT_9750, "Image 975"), - DEVICE( AI, AI_M1435, "M1435"), - DEVICE( MATROX, MATROX_MGA_2, "Atlas PX2085"), - DEVICE( MATROX, MATROX_MIL, "Millennium"), - DEVICE( MATROX, MATROX_MYS, "Mystique"), - DEVICE( MATROX, MATROX_MIL_2, "Millennium II"), - DEVICE( MATROX, MATROX_MGA_IMP, "MGA Impression"), - DEVICE( CT, CT_65545, "65545"), - DEVICE( CT, CT_65548, "65548"), - DEVICE( CT, CT_65550, "65550"), - DEVICE( CT, CT_65554, "65554"), - DEVICE( MIRO, MIRO_36050, "ZR36050"), - DEVICE( NEC, NEC_PCX2, "PowerVR PCX2"), - DEVICE( FD, FD_36C70, "TMC-18C30"), - DEVICE( SI, SI_6201, "6201"), - DEVICE( SI, SI_6202, "6202"), - DEVICE( SI, SI_503, "85C503"), - DEVICE( SI, SI_6205, "6205"), - DEVICE( SI, SI_501, "85C501"), - DEVICE( SI, SI_496, "85C496"), - DEVICE( SI, SI_601, "85C601"), - DEVICE( SI, SI_5107, "5107"), - DEVICE( SI, SI_5511, "85C5511"), - DEVICE( SI, SI_5513, "85C5513"), - DEVICE( SI, SI_5571, "5571"), - DEVICE( SI, SI_5597, "5597"), - DEVICE( SI, SI_7001, "7001"), - DEVICE( HP, HP_J2585A, "J2585A"), - DEVICE( HP, HP_J2585B, "J2585B (Lassen)"), - DEVICE( PCTECH, PCTECH_RZ1000, "RZ1000 (buggy)"), - DEVICE( PCTECH, PCTECH_RZ1001, "RZ1001 (buggy?)"), - DEVICE( DPT, DPT, "SmartCache/Raid"), - DEVICE( OPTI, OPTI_92C178, "92C178"), - DEVICE( OPTI, OPTI_82C557, "82C557 Viper-M"), - DEVICE( OPTI, OPTI_82C558, "82C558 Viper-M ISA+IDE"), - DEVICE( OPTI, OPTI_82C621, "82C621"), - DEVICE( OPTI, OPTI_82C700, "82C700"), - DEVICE( OPTI, OPTI_82C701, "82C701 FireStar Plus"), - DEVICE( OPTI, OPTI_82C814, "82C814 Firebridge 1"), - DEVICE( OPTI, OPTI_82C822, "82C822"), - DEVICE( SGS, SGS_2000, "STG 2000X"), - DEVICE( SGS, SGS_1764, "STG 1764X"), - DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER_NC, "MultiMaster NC"), - DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER, "MultiMaster"), - DEVICE( BUSLOGIC, BUSLOGIC_FLASHPOINT, "FlashPoint"), - DEVICE( TI, TI_TVP4010, "TVP4010 Permedia"), - DEVICE( TI, TI_TVP4020, "TVP4020 Permedia 2"), - DEVICE( TI, TI_PCI1130, "PCI1130"), - DEVICE( TI, TI_PCI1131, "PCI1131"), - DEVICE( OAK, OAK_OTI107, "OTI107"), - DEVICE( WINBOND2, WINBOND2_89C940,"NE2000-PCI"), - DEVICE( MOTOROLA, MOTOROLA_MPC105,"MPC105 Eagle"), - DEVICE( MOTOROLA, MOTOROLA_MPC106,"MPC106 Grackle"), - DEVICE( MOTOROLA, MOTOROLA_RAVEN, "Raven"), - DEVICE( PROMISE, PROMISE_20246, "IDE UltraDMA/33"), - DEVICE( PROMISE, PROMISE_5300, "DC5030"), - DEVICE( N9, N9_I128, "Imagine 128"), - DEVICE( N9, N9_I128_2, "Imagine 128v2"), - DEVICE( UMC, UMC_UM8673F, "UM8673F"), - DEVICE( UMC, UMC_UM8891A, "UM8891A"), - DEVICE( UMC, UMC_UM8886BF, "UM8886BF"), - DEVICE( UMC, UMC_UM8886A, "UM8886A"), - DEVICE( UMC, UMC_UM8881F, "UM8881F"), - DEVICE( UMC, UMC_UM8886F, "UM8886F"), - DEVICE( UMC, UMC_UM9017F, "UM9017F"), - DEVICE( UMC, UMC_UM8886N, "UM8886N"), - DEVICE( UMC, UMC_UM8891N, "UM8891N"), - DEVICE( X, X_AGX016, "ITT AGX016"), - DEVICE( PICOP, PICOP_PT86C52X, "PT86C52x Vesuvius"), - DEVICE( APPLE, APPLE_BANDIT, "Bandit"), - DEVICE( APPLE, APPLE_GC, "Grand Central"), - DEVICE( APPLE, APPLE_HYDRA, "Hydra"), - DEVICE( NEXGEN, NEXGEN_82C501, "82C501"), - DEVICE( QLOGIC, QLOGIC_ISP1020, "ISP1020"), - DEVICE( QLOGIC, QLOGIC_ISP1022, "ISP1022"), - DEVICE( CYRIX, CYRIX_5510, "5510"), - DEVICE( CYRIX, CYRIX_PCI_MASTER,"PCI Master"), - DEVICE( CYRIX, CYRIX_5520, "5520"), - DEVICE( CYRIX, CYRIX_5530_LEGACY,"5530 Kahlua Legacy"), - DEVICE( CYRIX, CYRIX_5530_SMI, "5530 Kahlua SMI"), - DEVICE( CYRIX, CYRIX_5530_IDE, "5530 Kahlua IDE"), - DEVICE( CYRIX, CYRIX_5530_AUDIO,"5530 Kahlua Audio"), - DEVICE( CYRIX, CYRIX_5530_VIDEO,"5530 Kahlua Video"), - DEVICE( LEADTEK, LEADTEK_805, "S3 805"), - DEVICE( CONTAQ, CONTAQ_82C599, "82C599"), - DEVICE( OLICOM, OLICOM_OC3136, "OC-3136/3137"), - DEVICE( OLICOM, OLICOM_OC2315, "OC-2315"), - DEVICE( OLICOM, OLICOM_OC2325, "OC-2325"), - DEVICE( OLICOM, OLICOM_OC2183, "OC-2183/2185"), - DEVICE( OLICOM, OLICOM_OC2326, "OC-2326"), - DEVICE( OLICOM, OLICOM_OC6151, "OC-6151/6152"), - DEVICE( SUN, SUN_EBUS, "EBUS"), - DEVICE( SUN, SUN_HAPPYMEAL, "Happy Meal"), - DEVICE( SUN, SUN_PBM, "PCI Bus Module"), - DEVICE( CMD, CMD_640, "640 (buggy)"), - DEVICE( CMD, CMD_643, "643"), - DEVICE( CMD, CMD_646, "646"), - DEVICE( CMD, CMD_670, "670"), - DEVICE( VISION, VISION_QD8500, "QD-8500"), - DEVICE( VISION, VISION_QD8580, "QD-8580"), - DEVICE( BROOKTREE, BROOKTREE_848, "Bt848"), - DEVICE( SIERRA, SIERRA_STB, "STB Horizon 64"), - DEVICE( ACC, ACC_2056, "2056"), - DEVICE( WINBOND, WINBOND_83769, "W83769F"), - DEVICE( WINBOND, WINBOND_82C105, "SL82C105"), - DEVICE( WINBOND, WINBOND_83C553, "W83C553"), - DEVICE( DATABOOK, DATABOOK_87144, "DB87144"), - DEVICE( 3COM, 3COM_3C590, "3C590 10bT"), - DEVICE( 3COM, 3COM_3C595TX, "3C595 100bTX"), - DEVICE( 3COM, 3COM_3C595T4, "3C595 100bT4"), - DEVICE( 3COM, 3COM_3C595MII, "3C595 100b-MII"), - DEVICE( 3COM, 3COM_3C900TPO, "3C900 10bTPO"), - DEVICE( 3COM, 3COM_3C900COMBO,"3C900 10b Combo"), - DEVICE( 3COM, 3COM_3C905TX, "3C905 100bTX"), - DEVICE( SMC, SMC_EPIC100, "9432 TX"), - DEVICE( AL, AL_M1445, "M1445"), - DEVICE( AL, AL_M1449, "M1449"), - DEVICE( AL, AL_M1451, "M1451"), - DEVICE( AL, AL_M1461, "M1461"), - DEVICE( AL, AL_M1489, "M1489"), - DEVICE( AL, AL_M1511, "M1511"), - DEVICE( AL, AL_M1513, "M1513"), - DEVICE( AL, AL_M1521, "M1521"), - DEVICE( AL, AL_M1523, "M1523"), - DEVICE( AL, AL_M1531, "M1531 Aladdin IV"), - DEVICE( AL, AL_M1533, "M1533 Aladdin IV"), - DEVICE( AL, AL_M4803, "M4803"), - DEVICE( AL, AL_M5219, "M5219"), - DEVICE( AL, AL_M5229, "M5229 TXpro"), - DEVICE( SURECOM, SURECOM_NE34, "NE-34PCI LAN"), - DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2070, "Magicgraph NM2070"), - DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128V, "MagicGraph 128V"), - DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_128ZV, "MagicGraph 128ZV"), - DEVICE( NEOMAGIC, NEOMAGIC_MAGICGRAPH_NM2160, "MagicGraph NM2160"), - DEVICE( ASP, ASP_ABP940, "ABP940"), - DEVICE( ASP, ASP_ABP940U, "ABP940U"), - DEVICE( CERN, CERN_SPSB_PMC, "STAR/RD24 SCI-PCI (PMC)"), - DEVICE( CERN, CERN_SPSB_PCI, "STAR/RD24 SCI-PCI (PMC)"), - DEVICE( IMS, IMS_8849, "8849"), - DEVICE( TEKRAM2, TEKRAM2_690c, "DC690c"), - DEVICE( TUNDRA, TUNDRA_CA91C042,"CA91C042 Universe"), - DEVICE( AMCC, AMCC_MYRINET, "Myrinet PCI (M2-PCI-32)"), - DEVICE( AMCC, AMCC_S5933, "S5933 PCI44"), - DEVICE( AMCC, AMCC_S5933_HEPC3,"S5933 Traquair HEPC3"), - DEVICE( INTERG, INTERG_1680, "IGA-1680"), - DEVICE( INTERG, INTERG_1682, "IGA-1682"), - DEVICE( REALTEK, REALTEK_8029, "8029"), - DEVICE( REALTEK, REALTEK_8129, "8129"), - DEVICE( TRUEVISION, TRUEVISION_T1000,"TARGA 1000"), - DEVICE( INIT, INIT_320P, "320 P"), - DEVICE( VIA, VIA_82C505, "VT 82C505"), - DEVICE( VIA, VIA_82C561, "VT 82C561"), - DEVICE( VIA, VIA_82C586_1, "VT 82C586 Apollo IDE"), - DEVICE( VIA, VIA_82C576, "VT 82C576 3V"), - DEVICE( VIA, VIA_82C585, "VT 82C585 Apollo VP1/VPX"), - DEVICE( VIA, VIA_82C586_0, "VT 82C586 Apollo ISA"), - DEVICE( VIA, VIA_82C595, "VT 82C595 Apollo VP2"), - DEVICE( VIA, VIA_82C926, "VT 82C926 Amazon"), - DEVICE( VIA, VIA_82C416, "VT 82C416MV"), - DEVICE( VIA, VIA_82C595_97, "VT 82C595 Apollo VP2/97"), - DEVICE( VIA, VIA_82C586_2, "VT 82C586 Apollo USB"), - DEVICE( VIA, VIA_82C586_3, "VT 82C586B Apollo ACPI"), - DEVICE( VORTEX, VORTEX_GDT60x0, "GDT 60x0"), - DEVICE( VORTEX, VORTEX_GDT6000B,"GDT 6000b"), - DEVICE( VORTEX, VORTEX_GDT6x10, "GDT 6110/6510"), - DEVICE( VORTEX, VORTEX_GDT6x20, "GDT 6120/6520"), - DEVICE( VORTEX, VORTEX_GDT6530, "GDT 6530"), - DEVICE( VORTEX, VORTEX_GDT6550, "GDT 6550"), - DEVICE( VORTEX, VORTEX_GDT6x17, "GDT 6117/6517"), - DEVICE( VORTEX, VORTEX_GDT6x27, "GDT 6127/6527"), - DEVICE( VORTEX, VORTEX_GDT6537, "GDT 6537"), - DEVICE( VORTEX, VORTEX_GDT6557, "GDT 6557"), - DEVICE( VORTEX, VORTEX_GDT6x15, "GDT 6115/6515"), - DEVICE( VORTEX, VORTEX_GDT6x25, "GDT 6125/6525"), - DEVICE( VORTEX, VORTEX_GDT6535, "GDT 6535"), - DEVICE( VORTEX, VORTEX_GDT6555, "GDT 6555"), - DEVICE( VORTEX, VORTEX_GDT6x17RP,"GDT 6117RP/6517RP"), - DEVICE( VORTEX, VORTEX_GDT6x27RP,"GDT 6127RP/6527RP"), - DEVICE( VORTEX, VORTEX_GDT6537RP,"GDT 6537RP"), - DEVICE( VORTEX, VORTEX_GDT6557RP,"GDT 6557RP"), - DEVICE( VORTEX, VORTEX_GDT6x11RP,"GDT 6111RP/6511RP"), - DEVICE( VORTEX, VORTEX_GDT6x21RP,"GDT 6121RP/6521RP"), - DEVICE( VORTEX, VORTEX_GDT6x17RP1,"GDT 6117RP1/6517RP1"), - DEVICE( VORTEX, VORTEX_GDT6x27RP1,"GDT 6127RP1/6527RP1"), - DEVICE( VORTEX, VORTEX_GDT6537RP1,"GDT 6537RP1"), - DEVICE( VORTEX, VORTEX_GDT6557RP1,"GDT 6557RP1"), - DEVICE( VORTEX, VORTEX_GDT6x11RP1,"GDT 6111RP1/6511RP1"), - DEVICE( VORTEX, VORTEX_GDT6x21RP1,"GDT 6121RP1/6521RP1"), - DEVICE( VORTEX, VORTEX_GDT6x17RP2,"GDT 6117RP2/6517RP2"), - DEVICE( VORTEX, VORTEX_GDT6x27RP2,"GDT 6127RP2/6527RP2"), - DEVICE( VORTEX, VORTEX_GDT6537RP2,"GDT 6537RP2"), - DEVICE( VORTEX, VORTEX_GDT6557RP2,"GDT 6557RP2"), - DEVICE( VORTEX, VORTEX_GDT6x11RP2,"GDT 6111RP2/6511RP2"), - DEVICE( VORTEX, VORTEX_GDT6x21RP2,"GDT 6121RP2/6521RP2"), - DEVICE( EF, EF_ATM_FPGA, "155P-MF1 (FPGA)"), - DEVICE( EF, EF_ATM_ASIC, "155P-MF1 (ASIC)"), - DEVICE( FORE, FORE_PCA200PC, "PCA-200PC"), - DEVICE( FORE, FORE_PCA200E, "PCA-200E"), - DEVICE( IMAGINGTECH, IMAGINGTECH_ICPCI, "MVC IC-PCI"), - DEVICE( PHILIPS, PHILIPS_SAA7146,"SAA7146"), - DEVICE( PLX, PLX_9060, "PCI9060 i960 bridge"), - DEVICE( ALLIANCE, ALLIANCE_PROMOTIO, "Promotion-6410"), - DEVICE( ALLIANCE, ALLIANCE_PROVIDEO, "Provideo"), - DEVICE( ALLIANCE, ALLIANCE_AT24, "AT24"), - DEVICE( ALLIANCE, ALLIANCE_AT3D, "AT3D"), - DEVICE( VMIC, VMIC_VME, "VMIVME-7587"), - DEVICE( DIGI, DIGI_RIGHTSWITCH, "RightSwitch SE-6"), - DEVICE( MUTECH, MUTECH_MV1000, "MV-1000"), - DEVICE( RENDITION, RENDITION_VERITE,"Verite 1000"), - DEVICE( RENDITION, RENDITION_VERITE2100,"Verite 2100"), - DEVICE( TOSHIBA, TOSHIBA_601, "Laptop"), - DEVICE( RICOH, RICOH_RL5C466, "RL5C466"), - DEVICE( ZEITNET, ZEITNET_1221, "1221"), - DEVICE( ZEITNET, ZEITNET_1225, "1225"), - DEVICE( OMEGA, OMEGA_82C092G, "82C092G"), - DEVICE( LITEON, LITEON_LNE100TX,"LNE100TX"), - DEVICE( NP, NP_PCI_FDDI, "NP-PCI"), - DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"), - DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"), - DEVICE( AURAVISION, AURAVISION_VXP524,"VXP524"), - DEVICE( IKON, IKON_10115, "10115 Greensheet"), - DEVICE( IKON, IKON_10117, "10117 Greensheet"), - DEVICE( ZORAN, ZORAN_36057, "ZR36057"), - DEVICE( ZORAN, ZORAN_36120, "ZR36120"), - DEVICE( COMPEX, COMPEX_ENET100VG4, "Readylink ENET100-VG4"), - DEVICE( COMPEX, COMPEX_RL2000, "ReadyLink 2000"), - DEVICE( RP, RP8OCTA, "RocketPort 8 Oct"), - DEVICE( RP, RP8INTF, "RocketPort 8 Intf"), - DEVICE( RP, RP16INTF, "RocketPort 16 Intf"), - DEVICE( RP, RP32INTF, "RocketPort 32 Intf"), - 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( 3DFX, 3DFX_VOODOO, "Voodoo"), - DEVICE( STALLION, STALLION_ECHPCI832,"EasyConnection 8/32"), - DEVICE( STALLION, STALLION_ECHPCI864,"EasyConnection 8/64"), - DEVICE( STALLION, STALLION_EIOPCI,"EasyIO"), - DEVICE( SIGMADES, SIGMADES_6425, "REALmagic64/GX"), - DEVICE( OPTIBASE, OPTIBASE_FORGE, "MPEG Forge"), - DEVICE( OPTIBASE, OPTIBASE_FUSION,"MPEG Fusion"), - DEVICE( OPTIBASE, OPTIBASE_VPLEX, "VideoPlex"), - DEVICE( OPTIBASE, OPTIBASE_VPLEXCC,"VideoPlex CC"), - DEVICE( OPTIBASE, OPTIBASE_VQUEST,"VideoQuest"), - DEVICE( ENSONIQ, ENSONIQ_AUDIOPCI,"AudioPCI"), - DEVICE( PICTUREL, PICTUREL_PCIVST,"PCIVST"), - DEVICE( NVIDIA_SGS, NVIDIA_SGS_RIVA128, "Riva 128"), - DEVICE( SYMPHONY, SYMPHONY_101, "82C101"), - DEVICE( TEKRAM, TEKRAM_DC290, "DC-290"), - DEVICE( 3DLABS, 3DLABS_300SX, "GLINT 300SX"), - DEVICE( 3DLABS, 3DLABS_500TX, "GLINT 500TX"), - DEVICE( 3DLABS, 3DLABS_DELTA, "GLINT Delta"), - DEVICE( 3DLABS, 3DLABS_PERMEDIA,"PERMEDIA"), - DEVICE( AVANCE, AVANCE_ALG2064, "ALG2064i"), - DEVICE( AVANCE, AVANCE_2302, "ALG-2302"), - DEVICE( NETVIN, NETVIN_NV5000SC,"NV5000"), - DEVICE( S3, S3_PLATO_PXS, "PLATO/PX (system)"), - DEVICE( S3, S3_ViRGE, "ViRGE"), - DEVICE( S3, S3_TRIO, "Trio32/Trio64"), - DEVICE( S3, S3_AURORA64VP, "Aurora64V+"), - DEVICE( S3, S3_TRIO64UVP, "Trio64UV+"), - DEVICE( S3, S3_ViRGE_VX, "ViRGE/VX"), - DEVICE( S3, S3_868, "Vision 868"), - DEVICE( S3, S3_928, "Vision 928-P"), - DEVICE( S3, S3_864_1, "Vision 864-P"), - DEVICE( S3, S3_864_2, "Vision 864-P"), - DEVICE( S3, S3_964_1, "Vision 964-P"), - DEVICE( S3, S3_964_2, "Vision 964-P"), - DEVICE( S3, S3_968, "Vision 968"), - DEVICE( S3, S3_TRIO64V2, "Trio64V2/DX or /GX"), - DEVICE( S3, S3_PLATO_PXG, "PLATO/PX (graphics)"), - DEVICE( S3, S3_ViRGE_DXGX, "ViRGE/DX or /GX"), - DEVICE( S3, S3_ViRGE_GX2, "ViRGE/GX2"), - DEVICE( S3, S3_ViRGE_MX, "ViRGE/MX"), - DEVICE( S3, S3_ViRGE_MXP, "ViRGE/MX+"), - DEVICE( S3, S3_ViRGE_MXPMV, "ViRGE/MX+MV"), - DEVICE( INTEL, INTEL_82375, "82375EB"), - DEVICE( INTEL, INTEL_82424, "82424ZX Saturn"), - DEVICE( INTEL, INTEL_82378, "82378IB"), - DEVICE( INTEL, INTEL_82430, "82430ZX Aries"), - DEVICE( INTEL, INTEL_82434, "82434LX Mercury/Neptune"), - DEVICE( INTEL, INTEL_82092AA_0,"82092AA PCMCIA bridge"), - DEVICE( INTEL, INTEL_82092AA_1,"82092AA EIDE"), - DEVICE( INTEL, INTEL_7116, "SAA7116"), - DEVICE( INTEL, INTEL_82596, "82596"), - DEVICE( INTEL, INTEL_82865, "82865"), - DEVICE( INTEL, INTEL_82557, "82557"), - DEVICE( INTEL, INTEL_82437, "82437"), - DEVICE( INTEL, INTEL_82371FB_0,"82371FB PIIX ISA"), - DEVICE( INTEL, INTEL_82371FB_1,"82371FB PIIX IDE"), - DEVICE( INTEL, INTEL_82371MX, "430MX - 82371MX MPIIX"), - DEVICE( INTEL, INTEL_82437MX, "430MX - 82437MX MTSC"), - DEVICE( INTEL, INTEL_82441, "82441FX Natoma"), - DEVICE( INTEL, INTEL_82439, "82439HX Triton II"), - DEVICE( INTEL, INTEL_82371SB_0,"82371SB PIIX3 ISA"), - DEVICE( INTEL, INTEL_82371SB_1,"82371SB PIIX3 IDE"), - DEVICE( INTEL, INTEL_82371SB_2,"82371SB PIIX3 USB"), - DEVICE( INTEL, INTEL_82437VX, "82437VX Triton II"), - DEVICE( INTEL, INTEL_82439TX, "82439TX"), - DEVICE( INTEL, INTEL_82371AB_0,"82371AB PIIX4 ISA"), - DEVICE( INTEL, INTEL_82371AB, "82371AB PIIX4 IDE"), - DEVICE( INTEL, INTEL_82371AB_2,"82371AB PIIX4 USB"), - DEVICE( INTEL, INTEL_82371AB_3,"82371AB PIIX4 ACPI"), - DEVICE( INTEL, INTEL_82443LX_0,"440LX - 82443LX PAC Host"), - DEVICE( INTEL, INTEL_82443LX_1,"440LX - 82443LX PAC AGP"), - DEVICE( INTEL, INTEL_P6, "Orion P6"), - DEVICE( INTEL, INTEL_82450GX, "82450GX Orion P6"), - DEVICE( KTI, KTI_ET32P2, "ET32P2"), - DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"), - DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"), - DEVICE( ADAPTEC, ADAPTEC_5800, "AIC-5800"), - DEVICE( ADAPTEC, ADAPTEC_7860, "AIC-7860"), - DEVICE( ADAPTEC, ADAPTEC_7861, "AIC-7861"), - DEVICE( ADAPTEC, ADAPTEC_7870, "AIC-7870"), - DEVICE( ADAPTEC, ADAPTEC_7871, "AIC-7871"), - DEVICE( ADAPTEC, ADAPTEC_7872, "AIC-7872"), - DEVICE( ADAPTEC, ADAPTEC_7873, "AIC-7873"), - DEVICE( ADAPTEC, ADAPTEC_7874, "AIC-7874"), - DEVICE( ADAPTEC, ADAPTEC_7895, "AIC-7895U"), - DEVICE( ADAPTEC, ADAPTEC_7880, "AIC-7880U"), - DEVICE( ADAPTEC, ADAPTEC_7881, "AIC-7881U"), - DEVICE( ADAPTEC, ADAPTEC_7882, "AIC-7882U"), - DEVICE( ADAPTEC, ADAPTEC_7883, "AIC-7883U"), - DEVICE( ADAPTEC, ADAPTEC_7884, "AIC-7884U"), - DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL"), - DEVICE( ARK, ARK_STING, "Stingray"), - DEVICE( ARK, ARK_STINGARK, "Stingray ARK 2000PV"), - DEVICE( ARK, ARK_2000MT, "2000MT") -}; - - -/* - * device_info[] is sorted so we can use binary search + * pci_malloc() returns initialized memory of size SIZE. Can be + * used only while pci_init() is active. */ -struct pci_dev_info *pci_lookup_dev(unsigned int vendor, unsigned int dev) -{ - int min = 0, - max = sizeof(dev_info)/sizeof(dev_info[0]) - 1; - - for ( ; ; ) - { - int i = (min + max) >> 1; - long order; - - order = dev_info[i].vendor - (long) vendor; - if (!order) - order = dev_info[i].device - (long) dev; - - if (order < 0) - { - min = i + 1; - if ( min > max ) - return 0; - continue; - } - - if (order > 0) - { - max = i - 1; - if ( min > max ) - return 0; - continue; - } - - return & dev_info[ i ]; - } -} - -const char *pci_strclass (unsigned int class) -{ - switch (class >> 8) { - case PCI_CLASS_NOT_DEFINED: return "Non-VGA device"; - case PCI_CLASS_NOT_DEFINED_VGA: return "VGA compatible device"; - - case PCI_CLASS_STORAGE_SCSI: return "SCSI bus controller"; - case PCI_CLASS_STORAGE_IDE: return "IDE controller"; - case PCI_CLASS_STORAGE_FLOPPY: return "Floppy disk controller"; - case PCI_CLASS_STORAGE_IPI: return "IPI bus controller"; - case PCI_CLASS_STORAGE_RAID: return "RAID controller"; - case PCI_CLASS_STORAGE_OTHER: return "Unknown mass storage controller"; - - case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet controller"; - case PCI_CLASS_NETWORK_TOKEN_RING: return "Token ring network controller"; - case PCI_CLASS_NETWORK_FDDI: return "FDDI network controller"; - case PCI_CLASS_NETWORK_ATM: return "ATM network controller"; - case PCI_CLASS_NETWORK_OTHER: return "Network controller"; - - case PCI_CLASS_DISPLAY_VGA: return "VGA compatible controller"; - case PCI_CLASS_DISPLAY_XGA: return "XGA compatible controller"; - case PCI_CLASS_DISPLAY_OTHER: return "Display controller"; - - case PCI_CLASS_MULTIMEDIA_VIDEO: return "Multimedia video controller"; - case PCI_CLASS_MULTIMEDIA_AUDIO: return "Multimedia audio controller"; - case PCI_CLASS_MULTIMEDIA_OTHER: return "Multimedia controller"; - - case PCI_CLASS_MEMORY_RAM: return "RAM memory"; - case PCI_CLASS_MEMORY_FLASH: return "FLASH memory"; - case PCI_CLASS_MEMORY_OTHER: return "Memory"; - - case PCI_CLASS_BRIDGE_HOST: return "Host bridge"; - case PCI_CLASS_BRIDGE_ISA: return "ISA bridge"; - case PCI_CLASS_BRIDGE_EISA: return "EISA bridge"; - case PCI_CLASS_BRIDGE_MC: return "MicroChannel bridge"; - case PCI_CLASS_BRIDGE_PCI: return "PCI bridge"; - case PCI_CLASS_BRIDGE_PCMCIA: return "PCMCIA bridge"; - case PCI_CLASS_BRIDGE_NUBUS: return "NuBus bridge"; - case PCI_CLASS_BRIDGE_CARDBUS: return "CardBus bridge"; - case PCI_CLASS_BRIDGE_OTHER: return "Bridge"; - - case PCI_CLASS_COMMUNICATION_SERIAL: return "Serial controller"; - case PCI_CLASS_COMMUNICATION_PARALLEL: return "Parallel controller"; - case PCI_CLASS_COMMUNICATION_OTHER: return "Communication controller"; - - case PCI_CLASS_SYSTEM_PIC: return "PIC"; - case PCI_CLASS_SYSTEM_DMA: return "DMA controller"; - case PCI_CLASS_SYSTEM_TIMER: return "Timer"; - case PCI_CLASS_SYSTEM_RTC: return "RTC"; - case PCI_CLASS_SYSTEM_OTHER: return "System peripheral"; - - case PCI_CLASS_INPUT_KEYBOARD: return "Keyboard controller"; - case PCI_CLASS_INPUT_PEN: return "Digitizer Pen"; - case PCI_CLASS_INPUT_MOUSE: return "Mouse controller"; - case PCI_CLASS_INPUT_OTHER: return "Input device controller"; - - case PCI_CLASS_DOCKING_GENERIC: return "Generic Docking Station"; - case PCI_CLASS_DOCKING_OTHER: return "Docking Station"; - - case PCI_CLASS_PROCESSOR_386: return "386"; - case PCI_CLASS_PROCESSOR_486: return "486"; - case PCI_CLASS_PROCESSOR_PENTIUM: return "Pentium"; - case PCI_CLASS_PROCESSOR_ALPHA: return "Alpha"; - case PCI_CLASS_PROCESSOR_POWERPC: return "Power PC"; - case PCI_CLASS_PROCESSOR_CO: return "Co-processor"; - - case PCI_CLASS_SERIAL_FIREWIRE: return "FireWire (IEEE 1394)"; - case PCI_CLASS_SERIAL_ACCESS: return "ACCESS Bus"; - case PCI_CLASS_SERIAL_SSA: return "SSA"; - case PCI_CLASS_SERIAL_USB: return "USB Controller"; - case PCI_CLASS_SERIAL_FIBER: return "Fiber Channel"; - - default: return "Unknown class"; - } -} - - -const char *pci_strvendor(unsigned int vendor) -{ - switch (vendor) { - case PCI_VENDOR_ID_COMPAQ: return "Compaq"; - case PCI_VENDOR_ID_NCR: return "NCR"; - case PCI_VENDOR_ID_ATI: return "ATI"; - case PCI_VENDOR_ID_VLSI: return "VLSI"; - case PCI_VENDOR_ID_ADL: return "Avance Logic"; - case PCI_VENDOR_ID_NS: return "NS"; - case PCI_VENDOR_ID_TSENG: return "Tseng'Lab"; - case PCI_VENDOR_ID_WEITEK: return "Weitek"; - case PCI_VENDOR_ID_DEC: return "DEC"; - case PCI_VENDOR_ID_CIRRUS: return "Cirrus Logic"; - case PCI_VENDOR_ID_IBM: return "IBM"; - case PCI_VENDOR_ID_WD: return "Western Digital"; - case PCI_VENDOR_ID_AMD: return "AMD"; - case PCI_VENDOR_ID_TRIDENT: return "Trident"; - case PCI_VENDOR_ID_AI: return "Acer Incorporated"; - case PCI_VENDOR_ID_MATROX: return "Matrox"; - case PCI_VENDOR_ID_CT: return "Chips & Technologies"; - case PCI_VENDOR_ID_MIRO: return "Miro"; - case PCI_VENDOR_ID_NEC: return "NEC"; - case PCI_VENDOR_ID_FD: return "Future Domain"; - case PCI_VENDOR_ID_SI: return "Silicon Integrated Systems"; - case PCI_VENDOR_ID_HP: return "Hewlett Packard"; - case PCI_VENDOR_ID_PCTECH: return "PCTECH"; - case PCI_VENDOR_ID_DPT: return "DPT"; - case PCI_VENDOR_ID_OPTI: return "OPTi"; - case PCI_VENDOR_ID_SGS: return "SGS Thomson"; - case PCI_VENDOR_ID_BUSLOGIC: return "BusLogic"; - case PCI_VENDOR_ID_TI: return "Texas Instruments"; - case PCI_VENDOR_ID_OAK: return "OAK"; - case PCI_VENDOR_ID_WINBOND2: return "Winbond"; - case PCI_VENDOR_ID_MOTOROLA: return "Motorola"; - case PCI_VENDOR_ID_PROMISE: return "Promise Technology"; - case PCI_VENDOR_ID_N9: return "Number Nine"; - case PCI_VENDOR_ID_UMC: return "UMC"; - case PCI_VENDOR_ID_X: return "X TECHNOLOGY"; - case PCI_VENDOR_ID_PICOP: return "PicoPower"; - case PCI_VENDOR_ID_APPLE: return "Apple"; - case PCI_VENDOR_ID_NEXGEN: return "Nexgen"; - case PCI_VENDOR_ID_QLOGIC: return "Q Logic"; - case PCI_VENDOR_ID_CYRIX: return "Cyrix"; - case PCI_VENDOR_ID_LEADTEK: return "Leadtek Research"; - case PCI_VENDOR_ID_CONTAQ: return "Contaq"; - case PCI_VENDOR_ID_FOREX: return "Forex"; - case PCI_VENDOR_ID_OLICOM: return "Olicom"; - case PCI_VENDOR_ID_SUN: return "Sun Microsystems"; - case PCI_VENDOR_ID_CMD: return "CMD"; - case PCI_VENDOR_ID_VISION: return "Vision"; - case PCI_VENDOR_ID_BROOKTREE: return "Brooktree"; - case PCI_VENDOR_ID_SIERRA: return "Sierra"; - case PCI_VENDOR_ID_ACC: return "ACC MICROELECTRONICS"; - case PCI_VENDOR_ID_WINBOND: return "Winbond"; - case PCI_VENDOR_ID_DATABOOK: return "Databook"; - case PCI_VENDOR_ID_3COM: return "3Com"; - case PCI_VENDOR_ID_SMC: return "SMC"; - case PCI_VENDOR_ID_AL: return "Acer Labs"; - case PCI_VENDOR_ID_MITSUBISHI: return "Mitsubishi"; - case PCI_VENDOR_ID_SURECOM: return "Surecom"; - case PCI_VENDOR_ID_NEOMAGIC: return "Neomagic"; - case PCI_VENDOR_ID_ASP: return "Advanced System Products"; - case PCI_VENDOR_ID_CERN: return "CERN"; - case PCI_VENDOR_ID_NVIDIA: return "NVidia"; - case PCI_VENDOR_ID_IMS: return "IMS"; - case PCI_VENDOR_ID_TEKRAM2: return "Tekram"; - case PCI_VENDOR_ID_TUNDRA: return "Tundra"; - case PCI_VENDOR_ID_AMCC: return "AMCC"; - case PCI_VENDOR_ID_INTERG: return "Intergraphics"; - case PCI_VENDOR_ID_REALTEK: return "Realtek"; - case PCI_VENDOR_ID_TRUEVISION: return "Truevision"; - case PCI_VENDOR_ID_INIT: return "Initio Corp"; - case PCI_VENDOR_ID_VIA: return "VIA Technologies"; - case PCI_VENDOR_ID_VORTEX: return "VORTEX"; - case PCI_VENDOR_ID_EF: return "Efficient Networks"; - case PCI_VENDOR_ID_FORE: return "Fore Systems"; - case PCI_VENDOR_ID_IMAGINGTECH: return "Imaging Technology"; - case PCI_VENDOR_ID_PHILIPS: return "Philips"; - case PCI_VENDOR_ID_PLX: return "PLX"; - case PCI_VENDOR_ID_ALLIANCE: return "Alliance"; - case PCI_VENDOR_ID_VMIC: return "VMIC"; - case PCI_VENDOR_ID_DIGI: return "Digi Intl."; - case PCI_VENDOR_ID_MUTECH: return "Mutech"; - case PCI_VENDOR_ID_RENDITION: return "Rendition"; - case PCI_VENDOR_ID_TOSHIBA: return "Toshiba"; - case PCI_VENDOR_ID_RICOH: return "Ricoh"; - case PCI_VENDOR_ID_ZEITNET: return "ZeitNet"; - case PCI_VENDOR_ID_OMEGA: return "Omega Micro"; - case PCI_VENDOR_ID_LITEON: return "LiteOn"; - case PCI_VENDOR_ID_NP: return "Network Peripherals"; - case PCI_VENDOR_ID_SPECIALIX: return "Specialix"; - case PCI_VENDOR_ID_AURAVISION: return "Auravision"; - case PCI_VENDOR_ID_IKON: return "Ikon"; - case PCI_VENDOR_ID_ZORAN: return "Zoran"; - case PCI_VENDOR_ID_COMPEX: return "Compex"; - case PCI_VENDOR_ID_RP: return "Comtrol"; - case PCI_VENDOR_ID_CYCLADES: return "Cyclades"; - case PCI_VENDOR_ID_3DFX: return "3Dfx"; - case PCI_VENDOR_ID_STALLION: return "Stallion Technologies"; - case PCI_VENDOR_ID_SIGMADES: return "Sigma Designs"; - case PCI_VENDOR_ID_OPTIBASE: return "Optibase"; - case PCI_VENDOR_ID_ENSONIQ: return "Ensoniq"; - case PCI_VENDOR_ID_PICTUREL: return "Picture Elements"; - case PCI_VENDOR_ID_NVIDIA_SGS: return "NVidia/SGS Thomson"; - case PCI_VENDOR_ID_SYMPHONY: return "Symphony"; - case PCI_VENDOR_ID_TEKRAM: return "Tekram"; - case PCI_VENDOR_ID_3DLABS: return "3Dlabs"; - case PCI_VENDOR_ID_AVANCE: return "Avance"; - case PCI_VENDOR_ID_NETVIN: return "NetVin"; - case PCI_VENDOR_ID_S3: return "S3 Inc."; - case PCI_VENDOR_ID_INTEL: return "Intel"; - case PCI_VENDOR_ID_KTI: return "KTI"; - case PCI_VENDOR_ID_ADAPTEC: return "Adaptec"; - case PCI_VENDOR_ID_ATRONICS: return "Atronics"; - case PCI_VENDOR_ID_ARK: return "ARK Logic"; - default: return "Unknown vendor"; - } -} - - -const char *pci_strdev(unsigned int vendor, unsigned int device) +__initfunc(static void *pci_malloc(long size, unsigned long *mem_startp)) { - struct pci_dev_info *info; + void *mem; - info = pci_lookup_dev(vendor, device); - return info ? info->name : "Unknown device"; + mem = (void*) *mem_startp; + *mem_startp += (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + memset(mem, 0, size); + return mem; } @@ -704,10 +55,10 @@ case PCIBIOS_BAD_REGISTER_NUMBER: return "BAD_REGISTER_NUMBER"; - case PCIBIOS_SET_FAILED: + case PCIBIOS_SET_FAILED: return "SET_FAILED"; - case PCIBIOS_BUFFER_TOO_SMALL: + case PCIBIOS_BUFFER_TOO_SMALL: return "BUFFER_TOO_SMALL"; default: @@ -717,198 +68,10 @@ } -/* - * Convert some of the configuration space registers of the device at - * address (bus,devfn) into a string (possibly several lines each). - * The configuration string is stored starting at buf[len]. If the - * string would exceed the size of the buffer (SIZE), 0 is returned. - */ -static int sprint_dev_config(struct pci_dev *dev, char *buf, int size) -{ - unsigned long base; - unsigned int l, class_rev, bus, devfn; - unsigned short vendor, device, status; - unsigned char bist, latency, min_gnt, max_lat; - int reg, len = 0; - const char *str; - - bus = dev->bus->number; - devfn = dev->devfn; - - pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class_rev); - pcibios_read_config_word (bus, devfn, PCI_VENDOR_ID, &vendor); - pcibios_read_config_word (bus, devfn, PCI_DEVICE_ID, &device); - pcibios_read_config_word (bus, devfn, PCI_STATUS, &status); - pcibios_read_config_byte (bus, devfn, PCI_BIST, &bist); - pcibios_read_config_byte (bus, devfn, PCI_LATENCY_TIMER, &latency); - pcibios_read_config_byte (bus, devfn, PCI_MIN_GNT, &min_gnt); - pcibios_read_config_byte (bus, devfn, PCI_MAX_LAT, &max_lat); - if (len + 80 > size) { - return -1; - } - len += sprintf(buf + len, " Bus %2d, device %3d, function %2d:\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - - if (len + 80 > size) { - return -1; - } - len += sprintf(buf + len, " %s: %s %s (rev %d).\n ", - pci_strclass(class_rev >> 8), pci_strvendor(vendor), - pci_strdev(vendor, device), class_rev & 0xff); - - if (!pci_lookup_dev(vendor, device)) { - len += sprintf(buf + len, - "Vendor id=%x. Device id=%x.\n ", - vendor, device); - } - - str = 0; /* to keep gcc shut... */ - switch (status & PCI_STATUS_DEVSEL_MASK) { - case PCI_STATUS_DEVSEL_FAST: str = "Fast devsel. "; break; - case PCI_STATUS_DEVSEL_MEDIUM: str = "Medium devsel. "; break; - case PCI_STATUS_DEVSEL_SLOW: str = "Slow devsel. "; break; - } - if (len + strlen(str) > size) { - return -1; - } - len += sprintf(buf + len, str); - - if (status & PCI_STATUS_FAST_BACK) { -# define fast_b2b_capable "Fast back-to-back capable. " - if (len + strlen(fast_b2b_capable) > size) { - return -1; - } - len += sprintf(buf + len, fast_b2b_capable); -# undef fast_b2b_capable - } - - if (bist & PCI_BIST_CAPABLE) { -# define BIST_capable "BIST capable. " - if (len + strlen(BIST_capable) > size) { - return -1; - } - len += sprintf(buf + len, BIST_capable); -# undef BIST_capable - } - - if (dev->irq) { - if (len + 40 > size) { - return -1; - } - len += sprintf(buf + len, "IRQ %d. ", dev->irq); - } - - if (dev->master) { - if (len + 80 > size) { - return -1; - } - len += sprintf(buf + len, "Master Capable. "); - if (latency) - len += sprintf(buf + len, "Latency=%d. ", latency); - else - len += sprintf(buf + len, "No bursts. "); - if (min_gnt) - len += sprintf(buf + len, "Min Gnt=%d.", min_gnt); - if (max_lat) - len += sprintf(buf + len, "Max Lat=%d.", max_lat); - } - - for (reg = 0; reg < 6; reg++) { - if (len + 40 > size) { - return -1; - } - pcibios_read_config_dword(bus, devfn, - PCI_BASE_ADDRESS_0 + (reg << 2), &l); - if (l == 0xffffffff) - base = 0; - else - base = l; - if (!base) - continue; - - if (base & PCI_BASE_ADDRESS_SPACE_IO) { - len += sprintf(buf + len, - "\n I/O at 0x%lx [0x%lx].", - base & PCI_BASE_ADDRESS_IO_MASK, - dev->base_address[reg]); - } else { - const char *pref, *type = "unknown"; - - if (base & PCI_BASE_ADDRESS_MEM_PREFETCH) { - pref = "P"; - } else { - pref = "Non-p"; - } - switch (base & PCI_BASE_ADDRESS_MEM_TYPE_MASK) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - type = "32 bit"; break; - case PCI_BASE_ADDRESS_MEM_TYPE_1M: - type = "20 bit"; break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - type = "64 bit"; - /* read top 32 bit address of base addr: */ - reg += 4; - pcibios_read_config_dword(bus, devfn, reg, &l); - base |= ((u64) l) << 32; - break; - } - len += sprintf(buf + len, - "\n %srefetchable %s memory at " - "0x%lx [0x%lx].", pref, type, - base & PCI_BASE_ADDRESS_MEM_MASK, - dev->base_address[reg]); - } - } - - len += sprintf(buf + len, "\n"); - return len; -} - - -/* - * Return list of PCI devices as a character string for /proc/pci. - * BUF is a buffer that is PAGE_SIZE bytes long. - */ -int get_pci_list(char *buf) -{ - int nprinted, len, size; - struct pci_dev *dev; -# define MSG "\nwarning: page-size limit reached!\n" - - /* reserve same for truncation warning message: */ - size = PAGE_SIZE - (strlen(MSG) + 1); - len = sprintf(buf, "PCI devices found:\n"); - - for (dev = pci_devices; dev; dev = dev->next) { - nprinted = sprint_dev_config(dev, buf + len, size - len); - if (nprinted < 0) { - return len + sprintf(buf + len, MSG); - } - len += nprinted; - } - return len; -} - - -/* - * pci_malloc() returns initialized memory of size SIZE. Can be - * used only while pci_init() is active. - */ -__initfunc(static void *pci_malloc(long size, unsigned long *mem_startp)) -{ - void *mem; - - mem = (void*) *mem_startp; - *mem_startp += (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1); - memset(mem, 0, size); - return mem; -} - unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp) { unsigned int devfn, l, max, class; unsigned char cmd, irq, tmp, hdr_type = 0; - struct pci_dev_info *info; struct pci_dev *dev; struct pci_bus *child; int reg; @@ -939,17 +102,6 @@ dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; - /* - * Check to see if we know about this device and report - * a message at boot time. This is the only way to - * learn about new hardware... - */ - info = pci_lookup_dev(dev->vendor, dev->device); - if (!info) { - printk("PCI: Warning: Unknown PCI device (%x:%x). Please read include/linux/pci.h\n", - dev->vendor, dev->device); - } - /* non-destructively determine if device can be a master: */ pcibios_read_config_byte(bus->number, devfn, PCI_COMMAND, &cmd); pcibios_write_config_byte(bus->number, devfn, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); @@ -1047,7 +199,7 @@ * has already been configured by the system. If so, * do not modify the configuration, merely note it. */ - pcibios_read_config_dword(bus->number, devfn, 0x18, &buses); + pcibios_read_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, &buses); if ((buses & 0xFFFFFF) != 0) { child->primary = buses & 0xFF; @@ -1066,7 +218,7 @@ (((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) | ((unsigned int)(child->subordinate) << 16)); - pcibios_write_config_dword(bus->number, devfn, 0x18, buses); + pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); /* * Now we can scan all subordinate buses: */ @@ -1078,7 +230,7 @@ child->subordinate = max; buses = (buses & 0xff00ffff) | ((unsigned int)(child->subordinate) << 16); - pcibios_write_config_dword(bus->number, devfn, 0x18, buses); + pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); } pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr); } @@ -1113,16 +265,6 @@ /* give BIOS a chance to apply platform specific fixes: */ mem_start = pcibios_fixup(mem_start, mem_end); - -#ifdef DEBUG - { - int len = get_pci_list((char*)mem_start); - if (len) { - ((char *) mem_start)[len] = '\0'; - printk("%s\n", (char *) mem_start); - } - } -#endif #ifdef CONFIG_PCI_OPTIMIZE pci_quirks_init(); diff -ur --new-file old/linux/drivers/pci/proc.c new/linux/drivers/pci/proc.c --- old/linux/drivers/pci/proc.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/pci/proc.c Sat Feb 21 03:28:22 1998 @@ -0,0 +1,291 @@ +/* + * $Id: proc.c,v 1.1 1997/12/22 17:22:31 mj Exp $ + * + * Procfs interface for the PCI bus. + * + * Copyright (c) 1997 Martin Mares + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCI_CFG_SPACE_SIZE 256 + +static loff_t +proc_bus_pci_lseek(struct file *file, loff_t off, int whence) +{ + loff_t new; + + switch (whence) { + case 0: + new = off; + break; + case 1: + new = file->f_pos + off; + break; + case 2: + new = PCI_CFG_SPACE_SIZE + off; + break; + default: + return -EINVAL; + } + if (new < 0 || new > PCI_CFG_SPACE_SIZE) + return -EINVAL; + return (file->f_pos = new); +} + +static ssize_t +proc_bus_pci_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) +{ + struct inode *ino = file->f_dentry->d_inode; + struct proc_dir_entry *dp = ino->u.generic_ip; + struct pci_dev *dev = dp->data; + int pos = *ppos; + unsigned char bus = dev->bus->number; + unsigned char dfn = dev->devfn; + int cnt; + + if (pos >= PCI_CFG_SPACE_SIZE) + return 0; + if (nbytes >= PCI_CFG_SPACE_SIZE) + nbytes = PCI_CFG_SPACE_SIZE; + if (pos + nbytes > PCI_CFG_SPACE_SIZE) + nbytes = PCI_CFG_SPACE_SIZE - pos; + cnt = nbytes; + + if (!access_ok(VERIFY_WRITE, buf, cnt)) + return -EINVAL; + + if ((pos & 1) && cnt) { + unsigned char val; + pcibios_read_config_byte(bus, dfn, pos, &val); + __put_user(val, buf); + buf++; + pos++; + cnt--; + } + + if ((pos & 3) && cnt > 2) { + unsigned short val; + pcibios_read_config_word(bus, dfn, pos, &val); + __put_user(cpu_to_le16(val), (unsigned short *) buf); + buf += 2; + pos += 2; + cnt -= 2; + } + + while (cnt >= 4) { + unsigned int val; + pcibios_read_config_dword(bus, dfn, pos, &val); + __put_user(cpu_to_le32(val), (unsigned int *) buf); + buf += 4; + pos += 4; + cnt -= 4; + } + + if (cnt >= 2) { + unsigned short val; + pcibios_read_config_word(bus, dfn, pos, &val); + __put_user(cpu_to_le16(val), (unsigned short *) buf); + buf += 2; + pos += 2; + cnt -= 2; + } + + if (cnt) { + unsigned char val; + pcibios_read_config_byte(bus, dfn, pos, &val); + __put_user(val, buf); + buf++; + pos++; + cnt--; + } + + *ppos = pos; + return nbytes; +} + +static ssize_t +proc_bus_pci_write(struct file *file, const char *buf, size_t nbytes, loff_t *ppos) +{ + struct inode *ino = file->f_dentry->d_inode; + struct proc_dir_entry *dp = ino->u.generic_ip; + struct pci_dev *dev = dp->data; + int pos = *ppos; + unsigned char bus = dev->bus->number; + unsigned char dfn = dev->devfn; + int cnt; + + if (pos >= PCI_CFG_SPACE_SIZE) + return 0; + if (nbytes >= PCI_CFG_SPACE_SIZE) + nbytes = PCI_CFG_SPACE_SIZE; + if (pos + nbytes > PCI_CFG_SPACE_SIZE) + nbytes = PCI_CFG_SPACE_SIZE - pos; + cnt = nbytes; + + if (!access_ok(VERIFY_READ, buf, cnt)) + return -EINVAL; + + if ((pos & 1) && cnt) { + unsigned char val; + __get_user(val, buf); + pcibios_write_config_byte(bus, dfn, pos, val); + buf++; + pos++; + cnt--; + } + + if ((pos & 3) && cnt > 2) { + unsigned short val; + __get_user(val, (unsigned short *) buf); + pcibios_write_config_word(bus, dfn, pos, le16_to_cpu(val)); + buf += 2; + pos += 2; + cnt -= 2; + } + + while (cnt >= 4) { + unsigned int val; + __get_user(val, (unsigned int *) buf); + pcibios_write_config_dword(bus, dfn, pos, le32_to_cpu(val)); + buf += 4; + pos += 4; + cnt -= 4; + } + + if (cnt >= 2) { + unsigned short val; + __get_user(val, (unsigned short *) buf); + pcibios_write_config_word(bus, dfn, pos, le16_to_cpu(val)); + buf += 2; + pos += 2; + cnt -= 2; + } + + if (cnt) { + unsigned char val; + __get_user(val, buf); + pcibios_write_config_byte(bus, dfn, pos, val); + buf++; + pos++; + cnt--; + } + + *ppos = pos; + return nbytes; +} + +static struct file_operations proc_bus_pci_operations = { + proc_bus_pci_lseek, + proc_bus_pci_read, + proc_bus_pci_write, + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +static struct inode_operations proc_bus_pci_inode_operations = { + &proc_bus_pci_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +int +get_pci_dev_info(char *buf, char **start, off_t pos, int count, int wr) +{ + struct pci_dev *dev = pci_devices; + off_t at = 0; + int len, i, cnt; + + cnt = 0; + while (dev && count > cnt) { + len = sprintf(buf, "%02x%02x\t%04x%04x\t%x", + dev->bus->number, + dev->devfn, + dev->vendor, + dev->device, + dev->irq); + for(i=0; i<6; i++) + len += sprintf(buf+len, +#if BITS_PER_LONG == 32 + "\t%08lx", +#else + "\t%016lx", +#endif + dev->base_address[i]); + buf[len++] = '\n'; + at += len; + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else + cnt += len; + buf += len; + } + dev = dev->next; + } + return (count > cnt) ? cnt : count; +} + +static struct proc_dir_entry proc_pci_devices = { + PROC_BUS_PCI_DEVICES, 7, "devices", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_array_inode_operations, + get_pci_dev_info +}; + +__initfunc(void proc_bus_pci_init(void)) +{ + struct proc_dir_entry *proc_pci; + struct pci_bus *bus; + + if (!pcibios_present()) + return; + proc_pci = create_proc_entry("pci", S_IFDIR, proc_bus); + proc_register(proc_pci, &proc_pci_devices); + for(bus = &pci_root; bus; bus = bus->next) { + char name[16]; + struct proc_dir_entry *de; + struct pci_dev *dev; + + sprintf(name, "%02x", bus->number); + de = create_proc_entry(name, S_IFDIR, proc_pci); + for(dev = bus->devices; dev; dev = dev->sibling) { + struct proc_dir_entry *e; + + sprintf(name, "%02x.%x", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, de); + e->ops = &proc_bus_pci_inode_operations; + e->data = dev; + e->size = PCI_CFG_SPACE_SIZE; + } + } +} diff -ur --new-file old/linux/drivers/pnp/parport_probe.c new/linux/drivers/pnp/parport_probe.c --- old/linux/drivers/pnp/parport_probe.c Tue Dec 2 18:38:15 1997 +++ new/linux/drivers/pnp/parport_probe.c Sat Jan 24 05:04:03 1998 @@ -58,7 +58,11 @@ for (i=0; ; i++) { parport_write_control(port, parport_read_control(port) | 2); /* AutoFeed high */ if (parport_wait_peripheral(port, 0x40, 0)) { +#ifdef DEBUG_PROBE + /* Some peripherals just time out when they've sent + all their data. */ printk("%s: read1 timeout.\n", port->name); +#endif parport_write_control(port, parport_read_control(port) & ~2); break; } @@ -68,36 +72,26 @@ printk("%s: read2 timeout.\n", port->name); break; } - if (( i & 1) != 0) { - Byte= (Byte | z<<4); + if ((i & 1) != 0) { + Byte |= (z<<4); if (temp) *(temp++) = Byte; if (count++ == length) temp = NULL; /* Does the error line indicate end of data? */ - if ((parport_read_status(port) & LP_PERRORP) == LP_PERRORP) + if ((parport_read_status(port) & LP_PERRORP) == + LP_PERRORP) break; - } else Byte=z; + } else + Byte=z; } read_terminate(port); return count; } -static struct wait_queue *wait_q; - -static void wakeup(void *ref) -{ - struct pardevice **dev = (struct pardevice **)ref; - - if (!waitqueue_active || parport_claim(*dev)) - return; - - wake_up(&wait_q); -} - int parport_probe(struct parport *port, char *buffer, int len) { - struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, wakeup, NULL, PARPORT_DEV_TRAN, &dev); + struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, PARPORT_DEV_TRAN, &dev); int result = 0; @@ -106,9 +100,7 @@ return -EINVAL; } - init_waitqueue (&wait_q); - if (parport_claim(dev)) - sleep_on(&wait_q); + parport_claim_or_block(dev); switch (parport_ieee1284_nibble_mode_ok(port, 4)) { case 1: @@ -233,6 +225,7 @@ char *buffer = kmalloc(2048, GFP_KERNEL); int r; + MOD_INC_USE_COUNT; port->probe_info.model = "Unknown device"; port->probe_info.mfr = "Unknown vendor"; port->probe_info.description = NULL; @@ -261,17 +254,16 @@ pretty_print(port); } kfree(buffer); + MOD_DEC_USE_COUNT; } #if MODULE int init_module(void) { struct parport *p; - MOD_INC_USE_COUNT; for (p = parport_enumerate(); p; p = p->next) parport_probe_one(p); parport_probe_hook = &parport_probe_one; - MOD_DEC_USE_COUNT; return 0; } diff -ur --new-file old/linux/drivers/sbus/audio/Makefile new/linux/drivers/sbus/audio/Makefile --- old/linux/drivers/sbus/audio/Makefile Tue Jan 13 00:15:45 1998 +++ new/linux/drivers/sbus/audio/Makefile Wed Feb 25 07:43:58 1998 @@ -16,37 +16,37 @@ M_OBJS := ifeq ($(CONFIG_SPARCAUDIO),y) -M=y +SBUS_AUDIO=y else ifeq ($(CONFIG_SPARCAUDIO),m) - MM=y + SBUS_AUDIO_MODULE=y endif endif ifeq ($(CONFIG_SPARCAUDIO_AMD7930),y) -M=y +SBUS_AUDIO=y OX_OBJS += amd7930.o else ifeq ($(CONFIG_SPARCAUDIO_AMD7930),m) - MM=y + SBUS_AUDIO_MODULE=y MX_OBJS += amd7930.o endif endif ifeq ($(CONFIG_SPARCAUDIO_CS4231),y) -M=y +SBUS_AUDIO=y O_OBJS += cs4231.o else ifeq ($(CONFIG_SPARCAUDIO_CS4231),m) - MM=y + SBUS_AUDIO_MODULE=y M_OBJS += cs4231.o endif endif -ifdef M +ifdef SBUS_AUDIO OX_OBJS += audio.o else - ifdef MM + ifdef SBUS_AUDIO_MODULE MX_OBJS += audio.o endif endif diff -ur --new-file old/linux/drivers/sbus/audio/amd7930.c new/linux/drivers/sbus/audio/amd7930.c --- old/linux/drivers/sbus/audio/amd7930.c Tue Jan 13 00:15:45 1998 +++ new/linux/drivers/sbus/audio/amd7930.c Sat Feb 21 03:28:22 1998 @@ -15,7 +15,6 @@ * databook which has all the programming information and gain tables. */ -#include #include #include #include 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 Tue Jan 13 00:15:45 1998 +++ new/linux/drivers/sbus/audio/cs4231.c Sat Feb 21 03:28:22 1998 @@ -8,7 +8,6 @@ * sun4m machines. */ -#include #include #include #include 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 Tue Jan 13 00:15:45 1998 +++ new/linux/drivers/sbus/char/flash.c Wed Feb 25 07:08:01 1998 @@ -134,7 +134,7 @@ flash_llseek, flash_read, NULL, /* no write to the Flash, use mmap - * and play flash dependant tricks. + * and play flash dependent tricks. */ NULL, /* readdir */ NULL, /* poll */ diff -ur --new-file old/linux/drivers/sbus/char/mach64.c new/linux/drivers/sbus/char/mach64.c --- old/linux/drivers/sbus/char/mach64.c Tue Jan 13 00:15:45 1998 +++ new/linux/drivers/sbus/char/mach64.c Sat Feb 21 03:28:22 1998 @@ -8,6 +8,7 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ +#include /* for CONFIG_CHIP_ID */ #include #include #include 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 Tue Jan 13 00:15:45 1998 +++ new/linux/drivers/sbus/char/pcikbd.c Fri Feb 27 18:11:40 1998 @@ -846,7 +846,7 @@ static unsigned int aux_poll(struct file *file, poll_table * wait) { - poll_wait(&queue->proc_list, wait); + poll_wait(file, &queue->proc_list, wait); if (aux_ready) return POLLIN | POLLRDNORM; return 0; 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 Tue Jan 13 00:15:45 1998 +++ new/linux/drivers/sbus/char/sunkbd.c Fri Feb 27 18:12:00 1998 @@ -1317,7 +1317,7 @@ static unsigned int kbd_poll (struct file *f, poll_table *wait) { - poll_wait(&kbd_wait, wait); + poll_wait(f, &kbd_wait, wait); if (kbd_head != kbd_tail) return POLLIN | POLLRDNORM; return 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 Tue Jan 13 00:15:45 1998 +++ new/linux/drivers/sbus/char/sunmouse.c Fri Feb 27 18:12:09 1998 @@ -420,7 +420,7 @@ static unsigned int sun_mouse_poll(struct file *file, poll_table *wait) { - poll_wait(&sunmouse.proc_list, wait); + poll_wait(file, &sunmouse.proc_list, wait); if(sunmouse.ready) return POLLIN | POLLRDNORM; return 0; 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 Thu Jul 17 04:22:51 1997 +++ new/linux/drivers/sbus/char/vfc_dev.c Thu Feb 12 01:19:56 1998 @@ -666,9 +666,6 @@ int vfc_init(void) #endif { -#ifdef MODULE - register_symtab(0); -#endif return vfc_probe(); } diff -ur --new-file old/linux/drivers/scsi/53c7,8xx.c new/linux/drivers/scsi/53c7,8xx.c --- old/linux/drivers/scsi/53c7,8xx.c Wed Aug 6 22:02:59 1997 +++ new/linux/drivers/scsi/53c7,8xx.c Sat Jan 24 02:38:04 1998 @@ -5958,7 +5958,7 @@ host->host_no, cmd->pid); /* print_dsa does sanity check on address, no need to check */ else - print_dsa (host, le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa), ""); + print_dsa (host, bus_to_virt(le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa)), ""); } else printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n", host->host_no, cmd->pid, cmd->target, cmd->lun); diff -ur --new-file old/linux/drivers/scsi/53c7xx.c new/linux/drivers/scsi/53c7xx.c --- old/linux/drivers/scsi/53c7xx.c Sat May 24 18:10:24 1997 +++ new/linux/drivers/scsi/53c7xx.c Sat Feb 21 03:28:22 1998 @@ -100,8 +100,6 @@ * the fourth byte from 50 to 25. */ -#include - /* * Sponsored by * iX Multiuser Multitasking Magazine @@ -233,7 +231,6 @@ #endif #include - #include #include #include diff -ur --new-file old/linux/drivers/scsi/BusLogic.c new/linux/drivers/scsi/BusLogic.c --- old/linux/drivers/scsi/BusLogic.c Mon Aug 11 09:10:00 1997 +++ new/linux/drivers/scsi/BusLogic.c Sat Jan 31 11:00:00 1998 @@ -6,8 +6,7 @@ This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation, provided that none of the source code or runtime - copyright notices are removed or modified. + Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY @@ -27,17 +26,17 @@ */ -#define BusLogic_DriverVersion "2.0.10" -#define BusLogic_DriverDate "11 August 1997" +#define BusLogic_DriverVersion "2.0.11" +#define BusLogic_DriverDate "31 January 1998" +#include #include #include #include #include #include #include -#include #include #include #include @@ -45,30 +44,43 @@ #include #include #include +#include #include #include "scsi.h" #include "hosts.h" #include "sd.h" #include "BusLogic.h" +#include "FlashPoint.c" /* - BusLogic_CommandLineEntryCount is a count of the number of "BusLogic=" - entries provided on the Linux Kernel Command Line. + BusLogic_DriverOptionsCount is a count of the number of BusLogic Driver + Options specifications provided via the Linux Kernel Command Line or via + the Loadable Kernel Module Installation Facility. */ static int - BusLogic_CommandLineEntryCount = 0; + BusLogic_DriverOptionsCount = 0; /* - BusLogic_CommandLineEntries is an array of Command Line Entry structures - representing the "BusLogic=" entries provided on the Linux Kernel Command - Line. + BusLogic_DriverOptions is an array of Driver Options structures representing + BusLogic Driver Options specifications provided via the Linux Kernel Command + Line or via the Loadable Kernel Module Installation Facility. */ -static BusLogic_CommandLineEntry_T - BusLogic_CommandLineEntries[BusLogic_MaxHostAdapters]; +static BusLogic_DriverOptions_T + BusLogic_DriverOptions[BusLogic_MaxHostAdapters]; + + +/* + BusLogic_Options can be assigned a string by the Loadable Kernel Module + Installation Facility to be parsed for BusLogic Driver Options + specifications. +*/ + +static char + *BusLogic_Options = NULL; /* @@ -77,7 +89,7 @@ */ static BusLogic_ProbeOptions_T - BusLogic_ProbeOptions = { 0 }; + BusLogic_ProbeOptions = { 0 }; /* @@ -86,7 +98,17 @@ */ static BusLogic_GlobalOptions_T - BusLogic_GlobalOptions = { 0 }; + BusLogic_GlobalOptions = { 0 }; + + +/* + BusLogic_FirstRegisteredHostAdapter and BusLogic_LastRegisteredHostAdapter + are pointers to the first and last registered BusLogic Host Adapters. +*/ + +static BusLogic_HostAdapter_T + *BusLogic_FirstRegisteredHostAdapter = NULL, + *BusLogic_LastRegisteredHostAdapter = NULL; /* @@ -99,11 +121,11 @@ /* - BusLogic_ProbeInfoCount is the numbers of entries in BusLogic_ProbeInfoList. + BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList. */ static int - BusLogic_ProbeInfoCount = 0; + BusLogic_ProbeInfoCount = 0; /* @@ -114,7 +136,7 @@ */ static BusLogic_ProbeInfo_T - BusLogic_ProbeInfoList[BusLogic_MaxHostAdapters] = { { 0 } }; + *BusLogic_ProbeInfoList = NULL; /* @@ -133,8 +155,8 @@ */ static BusLogic_CCB_T - *BusLogic_FirstCompletedCCB = NULL, - *BusLogic_LastCompletedCCB = NULL; + *BusLogic_FirstCompletedCCB = NULL, + *BusLogic_LastCompletedCCB = NULL; /* @@ -181,6 +203,17 @@ static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter) { + HostAdapter->NextAll = NULL; + if (BusLogic_FirstRegisteredHostAdapter == NULL) + { + BusLogic_FirstRegisteredHostAdapter = HostAdapter; + BusLogic_LastRegisteredHostAdapter = HostAdapter; + } + else + { + BusLogic_LastRegisteredHostAdapter->NextAll = HostAdapter; + BusLogic_LastRegisteredHostAdapter = HostAdapter; + } HostAdapter->Next = NULL; if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != NULL) { @@ -202,14 +235,33 @@ static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter) { + if (HostAdapter == BusLogic_FirstRegisteredHostAdapter) + { + BusLogic_FirstRegisteredHostAdapter = + BusLogic_FirstRegisteredHostAdapter->NextAll; + if (HostAdapter == BusLogic_LastRegisteredHostAdapter) + BusLogic_LastRegisteredHostAdapter = NULL; + } + else + { + BusLogic_HostAdapter_T *PreviousHostAdapter = + BusLogic_FirstRegisteredHostAdapter; + while (PreviousHostAdapter != NULL && + PreviousHostAdapter->NextAll != HostAdapter) + PreviousHostAdapter = PreviousHostAdapter->NextAll; + if (PreviousHostAdapter != NULL) + PreviousHostAdapter->NextAll = HostAdapter->NextAll; + } + HostAdapter->NextAll = NULL; if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != HostAdapter) { - BusLogic_HostAdapter_T *LastHostAdapter = + BusLogic_HostAdapter_T *PreviousHostAdapter = BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel]; - while (LastHostAdapter != NULL && LastHostAdapter->Next != HostAdapter) - LastHostAdapter = LastHostAdapter->Next; - if (LastHostAdapter != NULL) - LastHostAdapter->Next = HostAdapter->Next; + while (PreviousHostAdapter != NULL && + PreviousHostAdapter->Next != HostAdapter) + PreviousHostAdapter = PreviousHostAdapter->Next; + if (PreviousHostAdapter != NULL) + PreviousHostAdapter->Next = HostAdapter->Next; } else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] = HostAdapter->Next; @@ -218,85 +270,33 @@ /* - BusLogic_CreateMailboxes allocates the Outgoing and Incoming Mailboxes for - Host Adapter. -*/ - -static boolean BusLogic_CreateMailboxes(BusLogic_HostAdapter_T *HostAdapter) -{ - /* - FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; - /* - Allocate space for the Outgoing and Incoming Mailboxes. - */ - HostAdapter->FirstOutgoingMailbox = - (BusLogic_OutgoingMailbox_T *) - scsi_init_malloc(HostAdapter->MailboxCount - * (sizeof(BusLogic_OutgoingMailbox_T) - + sizeof(BusLogic_IncomingMailbox_T)), - (HostAdapter->BounceBuffersRequired - ? GFP_ATOMIC | GFP_DMA - : GFP_ATOMIC)); - if (HostAdapter->FirstOutgoingMailbox == NULL) - { - BusLogic_Error("UNABLE TO ALLOCATE MAILBOXES - DETACHING\n", - HostAdapter, HostAdapter->HostNumber); - return false; - } - HostAdapter->LastOutgoingMailbox = - HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1; - HostAdapter->FirstIncomingMailbox = - (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1); - HostAdapter->LastIncomingMailbox = - HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; - return true; -} - - -/* - BusLogic_DestroyMailboxes deallocates the Outgoing and Incoming Mailboxes - for Host Adapter. -*/ - -static void BusLogic_DestroyMailboxes(BusLogic_HostAdapter_T *HostAdapter) -{ - if (HostAdapter->FirstOutgoingMailbox == NULL) return; - scsi_init_free((char *) HostAdapter->FirstOutgoingMailbox, - HostAdapter->MailboxCount - * (sizeof(BusLogic_OutgoingMailbox_T) - + sizeof(BusLogic_IncomingMailbox_T))); -} - - -/* - BusLogic_CreateCCB allocates and initializes a single Command Control - Block (CCB) for Host Adapter, and adds it to Host Adapter's free list. -*/ - -static boolean BusLogic_CreateCCB(BusLogic_HostAdapter_T *HostAdapter) -{ - BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) - scsi_init_malloc(sizeof(BusLogic_CCB_T), - (HostAdapter->BounceBuffersRequired - ? GFP_ATOMIC | GFP_DMA - : GFP_ATOMIC)); - if (CCB == NULL) return false; - memset(CCB, 0, sizeof(BusLogic_CCB_T)); - CCB->HostAdapter = HostAdapter; - CCB->Status = BusLogic_CCB_Free; - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - CCB->CallbackFunction = BusLogic_QueueCompletedCCB; - CCB->BaseAddress = HostAdapter->IO_Address; + BusLogic_InitializeCCBs initializes a group of Command Control Blocks (CCBs) + for Host Adapter from the BlockSize bytes located at BlockPointer. The newly + created CCBs are added to Host Adapter's free list. +*/ + +static void BusLogic_InitializeCCBs(BusLogic_HostAdapter_T *HostAdapter, + void *BlockPointer, int BlockSize) +{ + BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) BlockPointer; + memset(BlockPointer, 0, BlockSize); + CCB->AllocationGroupHead = true; + while ((BlockSize -= sizeof(BusLogic_CCB_T)) >= 0) + { + CCB->Status = BusLogic_CCB_Free; + CCB->HostAdapter = HostAdapter; + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + { + CCB->CallbackFunction = BusLogic_QueueCompletedCCB; + CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress; + } + CCB->Next = HostAdapter->Free_CCBs; + CCB->NextAll = HostAdapter->All_CCBs; + HostAdapter->Free_CCBs = CCB; + HostAdapter->All_CCBs = CCB; + HostAdapter->AllocatedCCBs++; + CCB++; } - CCB->Next = HostAdapter->Free_CCBs; - CCB->NextAll = HostAdapter->All_CCBs; - HostAdapter->Free_CCBs = CCB; - HostAdapter->All_CCBs = CCB; - HostAdapter->AllocatedCCBs++; - return true; } @@ -306,14 +306,21 @@ static boolean BusLogic_CreateInitialCCBs(BusLogic_HostAdapter_T *HostAdapter) { - int Allocated; - for (Allocated = 0; Allocated < HostAdapter->InitialCCBs; Allocated++) - if (!BusLogic_CreateCCB(HostAdapter)) - { - BusLogic_Error("UNABLE TO ALLOCATE CCB %d - DETACHING\n", - HostAdapter, Allocated); - return false; - } + int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T); + while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) + { + void *BlockPointer = kmalloc(BlockSize, + (HostAdapter->BounceBuffersRequired + ? GFP_ATOMIC | GFP_DMA + : GFP_ATOMIC)); + if (BlockPointer == NULL) + { + BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", + HostAdapter); + return false; + } + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize); + } return true; } @@ -330,7 +337,8 @@ while ((CCB = NextCCB) != NULL) { NextCCB = CCB->NextAll; - scsi_init_free((char *) CCB, sizeof(BusLogic_CCB_T)); + if (CCB->AllocationGroupHead) + kfree(CCB); } } @@ -346,18 +354,35 @@ int AdditionalCCBs, boolean SuccessMessageP) { - int Allocated; + int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T); + int PreviouslyAllocated = HostAdapter->AllocatedCCBs; if (AdditionalCCBs <= 0) return; - for (Allocated = 0; Allocated < AdditionalCCBs; Allocated++) - if (!BusLogic_CreateCCB(HostAdapter)) break; - if (Allocated > 0 && SuccessMessageP) - BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", - HostAdapter, Allocated, HostAdapter->AllocatedCCBs); - if (Allocated > 0) return; + while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) + { + void *BlockPointer = kmalloc(BlockSize, + (HostAdapter->BounceBuffersRequired + ? GFP_ATOMIC | GFP_DMA + : GFP_ATOMIC)); + if (BlockPointer == NULL) break; + BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize); + } + if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) + { + if (SuccessMessageP) + BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", + HostAdapter, + HostAdapter->AllocatedCCBs - PreviouslyAllocated, + HostAdapter->AllocatedCCBs); + return; + } BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter); - HostAdapter->DriverQueueDepth = - HostAdapter->AllocatedCCBs - (HostAdapter->MaxTargetDevices - 1); - HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; + if (HostAdapter->DriverQueueDepth > + HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount) + { + HostAdapter->DriverQueueDepth = + HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount; + HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; + } } @@ -413,47 +438,6 @@ /* - BusLogic_CreateTargetDeviceStatistics creates the Target Device Statistics - structure for Host Adapter. -*/ - -static boolean BusLogic_CreateTargetDeviceStatistics(BusLogic_HostAdapter_T - *HostAdapter) -{ - HostAdapter->TargetDeviceStatistics = - (BusLogic_TargetDeviceStatistics_T *) - scsi_init_malloc(HostAdapter->MaxTargetDevices - * sizeof(BusLogic_TargetDeviceStatistics_T), - GFP_ATOMIC); - if (HostAdapter->TargetDeviceStatistics == NULL) - { - BusLogic_Error("UNABLE TO ALLOCATE TARGET DEVICE STATISTICS - " - "DETACHING\n", HostAdapter, HostAdapter->HostNumber); - return false; - } - memset(HostAdapter->TargetDeviceStatistics, 0, - HostAdapter->MaxTargetDevices - * sizeof(BusLogic_TargetDeviceStatistics_T)); - return true; -} - - -/* - BusLogic_DestroyTargetDeviceStatistics destroys the Target Device Statistics - structure for Host Adapter. -*/ - -static void BusLogic_DestroyTargetDeviceStatistics(BusLogic_HostAdapter_T - *HostAdapter) -{ - if (HostAdapter->TargetDeviceStatistics == NULL) return; - scsi_init_free((char *) HostAdapter->TargetDeviceStatistics, - HostAdapter->MaxTargetDevices - * sizeof(BusLogic_TargetDeviceStatistics_T)); -} - - -/* BusLogic_Command sends the command OperationCode to HostAdapter, optionally providing ParameterLength bytes of ParameterData and receiving at most ReplyLength bytes of ReplyData; any excess reply data is received but @@ -494,7 +478,7 @@ If the IRQ Channel has not yet been acquired, then interrupts must be disabled while issuing host adapter commands since a Command Complete interrupt could occur if the IRQ Channel was previously enabled by another - BusLogic Host Adapter or other driver sharing the same IRQ Channel. + BusLogic Host Adapter or another driver sharing the same IRQ Channel. */ if (!HostAdapter->IRQ_ChannelAcquired) { @@ -572,7 +556,7 @@ Result = -1; goto Done; } - if (BusLogic_GlobalOptions.Bits.TraceConfiguration) + if (BusLogic_GlobalOptions.TraceConfiguration) BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: " "(Modify I/O Address)\n", HostAdapter, OperationCode, StatusRegister.All); @@ -607,9 +591,11 @@ if (InterruptRegister.Bits.CommandComplete) break; if (HostAdapter->HostAdapterCommandCompleted) break; if (StatusRegister.Bits.DataInRegisterReady) - if (++ReplyBytes <= ReplyLength) - *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); - else BusLogic_ReadDataInRegister(HostAdapter); + { + if (++ReplyBytes <= ReplyLength) + *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); + else BusLogic_ReadDataInRegister(HostAdapter); + } if (OperationCode == BusLogic_FetchHostAdapterLocalRAM && StatusRegister.Bits.HostAdapterReady) break; udelay(100); @@ -621,34 +607,24 @@ goto Done; } /* - If testing Command Complete Interrupts, wait a short while in case the - loop immediately above terminated due to the Command Complete bit being - set in the Interrupt Register, but the interrupt hasn't actually been - processed yet. Otherwise, acknowledging the interrupt here could prevent - the interrupt test from succeeding. - */ - if (OperationCode == BusLogic_TestCommandCompleteInterrupt) - udelay(10000); - /* Clear any pending Command Complete Interrupt. */ BusLogic_InterruptReset(HostAdapter); /* Provide tracing information if requested. */ - if (BusLogic_GlobalOptions.Bits.TraceConfiguration) - if (OperationCode != BusLogic_TestCommandCompleteInterrupt) - { - int i; - BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", - HostAdapter, OperationCode, - StatusRegister.All, ReplyLength, ReplyBytes); - if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes; - for (i = 0; i < ReplyLength; i++) - BusLogic_Notice(" %02X", HostAdapter, - ((unsigned char *) ReplyData)[i]); - BusLogic_Notice("\n", HostAdapter); - } + if (BusLogic_GlobalOptions.TraceConfiguration) + { + int i; + BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", + HostAdapter, OperationCode, + StatusRegister.All, ReplyLength, ReplyBytes); + if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes; + for (i = 0; i < ReplyLength; i++) + BusLogic_Notice(" %02X", HostAdapter, + ((unsigned char *) ReplyData)[i]); + BusLogic_Notice("\n", HostAdapter); + } /* Process Command Invalid conditions. */ @@ -705,38 +681,63 @@ /* + BusLogic_AppendProbeAddressISA appends a single ISA I/O Address to the list + of I/O Address and Bus Probe Information to be checked for potential BusLogic + Host Adapters. +*/ + +static void BusLogic_AppendProbeAddressISA(BusLogic_IO_Address_T IO_Address) +{ + BusLogic_ProbeInfo_T *ProbeInfo; + if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return; + ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; + ProbeInfo->HostAdapterType = BusLogic_MultiMaster; + ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; + ProbeInfo->IO_Address = IO_Address; +} + + +/* BusLogic_InitializeProbeInfoListISA initializes the list of I/O Address and Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters only from the list of standard BusLogic MultiMaster ISA I/O Addresses. */ -static void BusLogic_InitializeProbeInfoListISA(void) +static void BusLogic_InitializeProbeInfoListISA(BusLogic_HostAdapter_T + *PrototypeHostAdapter) { - int StandardAddressIndex; - /* - If BusLogic_Setup has provided an I/O Address probe list, do not override - the Kernel Command Line specifications. - */ - if (BusLogic_ProbeInfoCount > 0) return; /* - If a Kernel Command Line specification has requested that ISA Bus Probes + If BusLogic Driver Options specifications requested that ISA Bus Probes be inhibited, do not proceed further. */ - if (BusLogic_ProbeOptions.Bits.NoProbeISA) return; + if (BusLogic_ProbeOptions.NoProbeISA) return; /* Append the list of standard BusLogic MultiMaster ISA I/O Addresses. */ - StandardAddressIndex = 0; - while (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters && - StandardAddressIndex < BusLogic_ISA_StandardAddressesCount) - { - BusLogic_ProbeInfo_T *ProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->IO_Address = - BusLogic_ISA_StandardAddresses[StandardAddressIndex++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - } + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe330 + : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x330); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe334 + : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x334); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe230 + : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x230); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe234 + : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x234); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe130 + : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x130); + if (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe134 + : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0) + BusLogic_AppendProbeAddressISA(0x134); } @@ -783,25 +784,26 @@ I/O Addresses. It returns the number of PCI MultiMaster Host Adapters found. */ -static int BusLogic_InitializeMultiMasterProbeInfo(void) +static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T + *PrototypeHostAdapter) { - boolean StandardAddressSeen[BusLogic_ISA_StandardAddressesCount]; BusLogic_ProbeInfo_T *PrimaryProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount]; int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1; int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0; boolean ForceBusDeviceScanningOrder = false; boolean ForceBusDeviceScanningOrderChecked = false; - unsigned char Bus, DeviceFunction, IRQ_Channel; + boolean StandardAddressSeen[6]; + unsigned char Bus, DeviceFunction; unsigned int BaseAddress0, BaseAddress1; + unsigned char IRQ_Channel; BusLogic_IO_Address_T IO_Address; BusLogic_PCI_Address_T PCI_Address; unsigned short Index = 0; - int StandardAddressIndex, i; - if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) - return 0; + int i; + if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return 0; BusLogic_ProbeInfoCount++; - for (i = 0; i < BusLogic_ISA_StandardAddressesCount; i++) + for (i = 0; i < 6; i++) StandardAddressSeen[i] = false; /* Iterate over the MultiMaster PCI Host Adapters. For each enumerated host @@ -826,8 +828,7 @@ pcibios_read_config_byte(Bus, DeviceFunction, PCI_INTERRUPT_LINE, &IRQ_Channel) == 0) { - BusLogic_HostAdapter_T HostAdapterPrototype; - BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype; + BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter; BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation; BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest; unsigned char Device = DeviceFunction >> 3; @@ -859,7 +860,7 @@ NULL, Bus, Device, IO_Address); continue; } - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) { BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter " "detected at\n", NULL); @@ -871,7 +872,7 @@ Issue the Inquire PCI Host Adapter Information command to determine the ISA Compatible I/O Port. If the ISA Compatible I/O Port is known and enabled, note that the particular Standard ISA I/O - Address need not be probed. + Address should not be probed. */ HostAdapter->IO_Address = IO_Address; if (BusLogic_Command(HostAdapter, @@ -880,8 +881,7 @@ sizeof(PCIHostAdapterInformation)) == sizeof(PCIHostAdapterInformation)) { - if (PCIHostAdapterInformation.ISACompatibleIOPort < - BusLogic_ISA_StandardAddressesCount) + if (PCIHostAdapterInformation.ISACompatibleIOPort < 6) StandardAddressSeen[PCIHostAdapterInformation .ISACompatibleIOPort] = true; } @@ -933,10 +933,10 @@ */ if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330) { - PrimaryProbeInfo->IO_Address = IO_Address; - PrimaryProbeInfo->PCI_Address = PCI_Address; PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + PrimaryProbeInfo->IO_Address = IO_Address; + PrimaryProbeInfo->PCI_Address = PCI_Address; PrimaryProbeInfo->Bus = Bus; PrimaryProbeInfo->Device = Device; PrimaryProbeInfo->IRQ_Channel = IRQ_Channel; @@ -946,10 +946,10 @@ { BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; ProbeInfo->HostAdapterType = BusLogic_MultiMaster; ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Address = PCI_Address; ProbeInfo->Bus = Bus; ProbeInfo->Device = Device; ProbeInfo->IRQ_Channel = IRQ_Channel; @@ -978,31 +978,48 @@ then the Primary I/O Address must be probed explicitly before any PCI host adapters are probed. */ - if (PrimaryProbeInfo->IO_Address == 0 && - !BusLogic_ProbeOptions.Bits.NoProbeISA) - { - PrimaryProbeInfo->IO_Address = BusLogic_ISA_StandardAddresses[0]; - PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; - PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - } + if (!BusLogic_ProbeOptions.NoProbeISA) + if (PrimaryProbeInfo->IO_Address == 0 && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe330 + : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) + { + PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; + PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; + PrimaryProbeInfo->IO_Address = 0x330; + } /* Append the list of standard BusLogic MultiMaster ISA I/O Addresses, omitting the Primary I/O Address which has already been handled. */ - if (!BusLogic_ProbeOptions.Bits.NoProbeISA) - for (StandardAddressIndex = 1; - StandardAddressIndex < BusLogic_ISA_StandardAddressesCount; - StandardAddressIndex++) - if (!StandardAddressSeen[StandardAddressIndex] && - BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) - { - BusLogic_ProbeInfo_T *ProbeInfo = - &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->IO_Address = - BusLogic_ISA_StandardAddresses[StandardAddressIndex]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - } + if (!BusLogic_ProbeOptions.NoProbeISA) + { + if (!StandardAddressSeen[1] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe334 + : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x334); + if (!StandardAddressSeen[2] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe230 + : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x230); + if (!StandardAddressSeen[3] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe234 + : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x234); + if (!StandardAddressSeen[4] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe130 + : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x130); + if (!StandardAddressSeen[5] && + (BusLogic_ProbeOptions.LimitedProbeISA + ? BusLogic_ProbeOptions.Probe134 + : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)) + BusLogic_AppendProbeAddressISA(0x134); + } return PCIMultiMasterCount; } @@ -1014,11 +1031,13 @@ number of FlashPoint Host Adapters found. */ -static int BusLogic_InitializeFlashPointProbeInfo(void) +static int BusLogic_InitializeFlashPointProbeInfo(BusLogic_HostAdapter_T + *PrototypeHostAdapter) { int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0; - unsigned char Bus, DeviceFunction, IRQ_Channel; + unsigned char Bus, DeviceFunction; unsigned int BaseAddress0, BaseAddress1; + unsigned char IRQ_Channel; BusLogic_IO_Address_T IO_Address; BusLogic_PCI_Address_T PCI_Address; unsigned short Index = 0; @@ -1065,7 +1084,7 @@ NULL, Bus, Device, IO_Address); continue; } - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) { BusLogic_Notice("BusLogic: FlashPoint Host Adapter " "detected at\n", NULL); @@ -1077,10 +1096,10 @@ { BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; ProbeInfo->HostAdapterType = BusLogic_FlashPoint; ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; + ProbeInfo->IO_Address = IO_Address; + ProbeInfo->PCI_Address = PCI_Address; ProbeInfo->Bus = Bus; ProbeInfo->Device = Device; ProbeInfo->IRQ_Channel = IRQ_Channel; @@ -1116,44 +1135,41 @@ FlashPoint and PCI MultiMaster Host Adapters are present, this driver will probe for FlashPoint Host Adapters first unless the BIOS primary disk is controlled by the first PCI MultiMaster Host Adapter, in which case - MultiMaster Host Adapters will be probed first. The Kernel Command Line - options "MultiMasterFirst" and "FlashPointFirst" can be used to force a - particular probe order. + MultiMaster Host Adapters will be probed first. The BusLogic Driver Options + specifications "MultiMasterFirst" and "FlashPointFirst" can be used to force + a particular probe order. */ -static void BusLogic_InitializeProbeInfoList(void) +static void BusLogic_InitializeProbeInfoList(BusLogic_HostAdapter_T + *PrototypeHostAdapter) { /* - If BusLogic_Setup has provided an I/O Address probe list, do not override - the Kernel Command Line specifications. - */ - if (BusLogic_ProbeInfoCount > 0) return; - /* If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint Host Adapters; otherwise, default to the standard ISA MultiMaster probe. */ - if (!BusLogic_ProbeOptions.Bits.NoProbePCI && pcibios_present()) + if (!BusLogic_ProbeOptions.NoProbePCI && pcibios_present()) { - if (BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst) + if (BusLogic_ProbeOptions.MultiMasterFirst) { - BusLogic_InitializeMultiMasterProbeInfo(); - BusLogic_InitializeFlashPointProbeInfo(); + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); } - else if (BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst) + else if (BusLogic_ProbeOptions.FlashPointFirst) { - BusLogic_InitializeFlashPointProbeInfo(); - BusLogic_InitializeMultiMasterProbeInfo(); + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); } else { - int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo(); - int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo(); + int FlashPointCount = + BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); + int PCIMultiMasterCount = + BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); if (FlashPointCount > 0 && PCIMultiMasterCount > 0) { BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[FlashPointCount]; - BusLogic_HostAdapter_T HostAdapterPrototype; - BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype; + BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter; BusLogic_FetchHostAdapterLocalRAMRequest_T FetchHostAdapterLocalRAMRequest; BusLogic_BIOSDriveMapByte_T Drive0MapByte; @@ -1195,7 +1211,7 @@ } } } - else BusLogic_InitializeProbeInfoListISA(); + else BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter); } @@ -1240,20 +1256,14 @@ */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - FlashPoint_Info_T *FlashPointInfo = (FlashPoint_Info_T *) - scsi_init_malloc(sizeof(FlashPoint_Info_T), GFP_ATOMIC); - int Retries = 10; - if (FlashPointInfo == NULL) - return BusLogic_Failure(HostAdapter, "ALLOCATING FLASHPOINT INFO"); - FlashPointInfo->BaseAddress = HostAdapter->IO_Address; + FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo; + FlashPointInfo->BaseAddress = + (BusLogic_Base_Address_T) HostAdapter->IO_Address; FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel; FlashPointInfo->Present = false; - while (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && - FlashPointInfo->Present) && - --Retries >= 0) ; - if (!FlashPointInfo->Present) + if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && + FlashPointInfo->Present)) { - scsi_init_free((char *) FlashPointInfo, sizeof(FlashPoint_Info_T)); BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device); @@ -1264,8 +1274,7 @@ HostAdapter); return false; } - HostAdapter->FlashPointInfo = FlashPointInfo; - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n", HostAdapter, HostAdapter->IO_Address); /* @@ -1283,7 +1292,7 @@ StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " "Geometry 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All, @@ -1318,12 +1327,16 @@ /* - BusLogic_HardResetHostAdapter issues a Hard Reset to the Host Adapter, - and waits for Host Adapter Diagnostics to complete. + BusLogic_HardwareResetHostAdapter issues a Hardware Reset to the Host Adapter + and waits for Host Adapter Diagnostics to complete. If HardReset is true, a + Hard Reset is performed which also initiates a SCSI Bus Reset. Otherwise, a + Soft Reset is performed which only resets the Host Adapter without forcing a + SCSI Bus Reset. */ -static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T - *HostAdapter) +static boolean BusLogic_HardwareResetHostAdapter(BusLogic_HostAdapter_T + *HostAdapter, + boolean HardReset) { BusLogic_StatusRegister_T StatusRegister; int TimeoutCounter; @@ -1332,9 +1345,11 @@ */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - HostAdapter->FlashPointInfo->ReportDataUnderrun = true; + FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo; + FlashPointInfo->HostSoftReset = !HardReset; + FlashPointInfo->ReportDataUnderrun = true; HostAdapter->CardHandle = - FlashPoint_HardResetHostAdapter(HostAdapter->FlashPointInfo); + FlashPoint_HardwareResetHostAdapter(FlashPointInfo); if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) return false; /* Indicate the Host Adapter Hard Reset completed successfully. @@ -1342,10 +1357,12 @@ return true; } /* - Issue a Hard Reset Command to the Host Adapter. The Host Adapter should - respond by setting Diagnostic Active in the Status Register. + Issue a Hard Reset or Soft Reset Command to the Host Adapter. The Host + Adapter should respond by setting Diagnostic Active in the Status Register. */ - BusLogic_HardReset(HostAdapter); + if (HardReset) + BusLogic_HardReset(HostAdapter); + else BusLogic_SoftReset(HostAdapter); /* Wait until Diagnostic Active is set in the Status Register. */ @@ -1356,8 +1373,8 @@ if (StatusRegister.Bits.DiagnosticActive) break; udelay(100); } - if (BusLogic_GlobalOptions.Bits.TraceHardReset) - BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Active, " + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); if (TimeoutCounter < 0) return false; @@ -1377,8 +1394,8 @@ if (!StatusRegister.Bits.DiagnosticActive) break; udelay(100); } - if (BusLogic_GlobalOptions.Bits.TraceHardReset) - BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Completed, " + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); if (TimeoutCounter < 0) return false; @@ -1396,8 +1413,8 @@ break; udelay(100); } - if (BusLogic_GlobalOptions.Bits.TraceHardReset) - BusLogic_Notice("BusLogic_HardReset(0x%X): Host Adapter Ready, " + if (BusLogic_GlobalOptions.TraceHardwareReset) + BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); if (TimeoutCounter < 0) return false; @@ -1447,25 +1464,27 @@ Issue the Inquire Configuration command if the IRQ Channel is unknown. */ if (HostAdapter->IRQ_Channel == 0) - if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, - NULL, 0, &Configuration, sizeof(Configuration)) - == sizeof(Configuration)) - { - if (Configuration.IRQ_Channel9) - HostAdapter->IRQ_Channel = 9; - else if (Configuration.IRQ_Channel10) - HostAdapter->IRQ_Channel = 10; - else if (Configuration.IRQ_Channel11) - HostAdapter->IRQ_Channel = 11; - else if (Configuration.IRQ_Channel12) - HostAdapter->IRQ_Channel = 12; - else if (Configuration.IRQ_Channel14) - HostAdapter->IRQ_Channel = 14; - else if (Configuration.IRQ_Channel15) - HostAdapter->IRQ_Channel = 15; - else Result = false; - } - else Result = false; + { + if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, + NULL, 0, &Configuration, sizeof(Configuration)) + == sizeof(Configuration)) + { + if (Configuration.IRQ_Channel9) + HostAdapter->IRQ_Channel = 9; + else if (Configuration.IRQ_Channel10) + HostAdapter->IRQ_Channel = 10; + else if (Configuration.IRQ_Channel11) + HostAdapter->IRQ_Channel = 11; + else if (Configuration.IRQ_Channel12) + HostAdapter->IRQ_Channel = 12; + else if (Configuration.IRQ_Channel14) + HostAdapter->IRQ_Channel = 14; + else if (Configuration.IRQ_Channel15) + HostAdapter->IRQ_Channel = 15; + else Result = false; + } + else Result = false; + } /* Issue the Inquire Extended Setup Information command. Only genuine BusLogic Host Adapters and true clones support this command. Adaptec 1542C @@ -1484,7 +1503,7 @@ /* Provide tracing information if requested and return. */ - if (BusLogic_GlobalOptions.Bits.TraceProbe) + if (BusLogic_GlobalOptions.TraceProbe) BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter, HostAdapter->IO_Address, (Result ? "Found" : "Not Found")); return Result; @@ -1512,7 +1531,7 @@ BusLogic_GeometryRegister_T GeometryRegister; BusLogic_RequestedReplyLength_T RequestedReplyLength; unsigned char *TargetPointer, Character; - int i; + int TargetID, i; /* Configuration Information for FlashPoint Host Adapters is provided in the FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function. @@ -1521,7 +1540,7 @@ */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - FlashPoint_Info_T *FlashPointInfo = HostAdapter->FlashPointInfo; + FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo; TargetPointer = HostAdapter->ModelName; *TargetPointer++ = 'B'; *TargetPointer++ = 'T'; @@ -1550,8 +1569,8 @@ HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); HostAdapter->MaxLogicalUnits = 32; - HostAdapter->InitialCCBs = 64; - HostAdapter->IncrementalCCBs = 16; + HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; + HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; HostAdapter->DriverQueueDepth = 255; HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth; HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted; @@ -1698,12 +1717,14 @@ HostAdapter->HostAdapterBusType = BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4']; if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus) - if (Configuration.DMA_Channel5) - HostAdapter->DMA_Channel = 5; - else if (Configuration.DMA_Channel6) - HostAdapter->DMA_Channel = 6; - else if (Configuration.DMA_Channel7) - HostAdapter->DMA_Channel = 7; + { + if (Configuration.DMA_Channel5) + HostAdapter->DMA_Channel = 5; + else if (Configuration.DMA_Channel6) + HostAdapter->DMA_Channel = 6; + else if (Configuration.DMA_Channel7) + HostAdapter->DMA_Channel = 7; + } /* Determine whether Extended Translation is enabled and save it in the Host Adapter structure. @@ -1837,7 +1858,7 @@ HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8); /* - Select appropriate values for the Driver Queue Depth, Mailbox Count, + Select appropriate values for the Mailbox Count, Driver Queue Depth, Initial CCBs, and Incremental CCBs variables based on whether or not Strict Round Robin Mode is supported. If Strict Round Robin Mode is supported, then there is no performance degradation in using the maximum possible @@ -1868,18 +1889,16 @@ if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) { HostAdapter->StrictRoundRobinModeSupport = true; - HostAdapter->MailboxCount = 255; - HostAdapter->InitialCCBs = 64; - HostAdapter->IncrementalCCBs = 16; + HostAdapter->MailboxCount = BusLogic_MaxMailboxes; } else { HostAdapter->StrictRoundRobinModeSupport = false; HostAdapter->MailboxCount = 32; - HostAdapter->InitialCCBs = 32; - HostAdapter->IncrementalCCBs = 8; } HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount; + HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; + HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; /* Tagged Queuing support is available and operates properly on all "W" series MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with @@ -1931,57 +1950,32 @@ */ Common: /* - Initialize the Host Adapter Name and Interrupt Label fields from the - Model Name. + Initialize the Host Adapter Full Model Name and Interrupt Label fields + from the Model Name. */ strcpy(HostAdapter->FullModelName, "BusLogic "); strcat(HostAdapter->FullModelName, HostAdapter->ModelName); strcpy(HostAdapter->InterruptLabel, HostAdapter->FullModelName); /* Select an appropriate value for the Tagged Queue Depth either from a - Command Line Entry, or based on whether this Host Adapter requires that ISA - Bounce Buffers be used. The Tagged Queue Depth is left at 0 for automatic - determination in BusLogic_SelectQueueDepths. Initialize the Untagged Queue - Depth. Tagged Queuing is disabled by default when the Tagged Queue Depth - is 1 since queuing multiple commands is not possible. - */ - if (HostAdapter->CommandLineEntry != NULL && - HostAdapter->CommandLineEntry->TaggedQueueDepth > 0) - HostAdapter->TaggedQueueDepth = - HostAdapter->CommandLineEntry->TaggedQueueDepth; - else if (HostAdapter->BounceBuffersRequired) - HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthBounceBuffers; - else HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthAutomatic; - HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth; - if (HostAdapter->UntaggedQueueDepth > HostAdapter->TaggedQueueDepth && - HostAdapter->TaggedQueueDepth > 0) - HostAdapter->UntaggedQueueDepth = HostAdapter->TaggedQueueDepth; - if (HostAdapter->TaggedQueueDepth == 1) - HostAdapter->TaggedQueuingPermitted = 0; - /* - Select an appropriate value for Bus Settle Time either from a Command - Line Entry, or from BusLogic_DefaultBusSettleTime. - */ - if (HostAdapter->CommandLineEntry != NULL && - HostAdapter->CommandLineEntry->BusSettleTime > 0) - HostAdapter->BusSettleTime = HostAdapter->CommandLineEntry->BusSettleTime; - else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; - /* - Select an appropriate value for Local Options from a Command Line Entry. - */ - if (HostAdapter->CommandLineEntry != NULL) - HostAdapter->LocalOptions = HostAdapter->CommandLineEntry->LocalOptions; - /* - Select appropriate values for the Error Recovery Strategy array either from - a Command Line Entry, or using BusLogic_ErrorRecovery_Default. - */ - if (HostAdapter->CommandLineEntry != NULL) - memcpy(HostAdapter->ErrorRecoveryStrategy, - HostAdapter->CommandLineEntry->ErrorRecoveryStrategy, - sizeof(HostAdapter->ErrorRecoveryStrategy)); - else memset(HostAdapter->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_Default, - sizeof(HostAdapter->ErrorRecoveryStrategy)); + BusLogic Driver Options specification, or based on whether this Host + Adapter requires that ISA Bounce Buffers be used. The Tagged Queue Depth + is left at 0 for automatic determination in BusLogic_SelectQueueDepths. + Initialize the Untagged Queue Depth. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + { + unsigned char QueueDepth = 0; + if (HostAdapter->DriverOptions != NULL && + HostAdapter->DriverOptions->QueueDepth[TargetID] > 0) + QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID]; + else if (HostAdapter->BounceBuffersRequired) + QueueDepth = BusLogic_TaggedQueueDepthBB; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + } + if (HostAdapter->BounceBuffersRequired) + HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB; + else HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth; /* Tagged Queuing is only allowed if Disconnect/Reconnect is permitted. Therefore, mask the Tagged Queuing Permitted Default bits with the @@ -1989,15 +1983,34 @@ */ HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted; /* - Combine the default Tagged Queuing Permitted bits with any Command - Line Entry Tagged Queuing specification. + Combine the default Tagged Queuing Permitted bits with any BusLogic Driver + Options Tagged Queuing specification. */ - if (HostAdapter->CommandLineEntry != NULL) + if (HostAdapter->DriverOptions != NULL) HostAdapter->TaggedQueuingPermitted = - (HostAdapter->CommandLineEntry->TaggedQueuingPermitted & - HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask) | + (HostAdapter->DriverOptions->TaggedQueuingPermitted & + HostAdapter->DriverOptions->TaggedQueuingPermittedMask) | (HostAdapter->TaggedQueuingPermitted & - ~HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask); + ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask); + /* + Select appropriate values for the Error Recovery Strategy array + either from a BusLogic Driver Options specification, or using + BusLogic_ErrorRecovery_Default. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + if (HostAdapter->DriverOptions != NULL) + HostAdapter->ErrorRecoveryStrategy[TargetID] = + HostAdapter->DriverOptions->ErrorRecoveryStrategy[TargetID]; + else HostAdapter->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_Default; + /* + Select an appropriate value for Bus Settle Time either from a BusLogic + Driver Options specification, or from BusLogic_DefaultBusSettleTime. + */ + if (HostAdapter->DriverOptions != NULL && + HostAdapter->DriverOptions->BusSettleTime > 0) + HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime; + else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; /* Indicate reading the Host Adapter Configuration completed successfully. */ @@ -2017,7 +2030,8 @@ unsigned short SynchronousPermitted, FastPermitted; unsigned short UltraPermitted, WidePermitted; unsigned short DisconnectPermitted, TaggedQueuingPermitted; - boolean CommonSynchronousNegotiation, CommonErrorRecovery; + boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth; + boolean CommonErrorRecovery; char SynchronousString[BusLogic_MaxTargetDevices+1]; char WideString[BusLogic_MaxTargetDevices+1]; char DisconnectString[BusLogic_MaxTargetDevices+1]; @@ -2083,22 +2097,26 @@ CommonSynchronousNegotiation = true; } else if (SynchronousPermitted == AllTargetsMask) - if (FastPermitted == 0) - { - SynchronousMessage = "Slow"; - CommonSynchronousNegotiation = true; - } - else if (FastPermitted == AllTargetsMask) - if (UltraPermitted == 0) + { + if (FastPermitted == 0) { - SynchronousMessage = "Fast"; + SynchronousMessage = "Slow"; CommonSynchronousNegotiation = true; } - else if (UltraPermitted == AllTargetsMask) + else if (FastPermitted == AllTargetsMask) { - SynchronousMessage = "Ultra"; - CommonSynchronousNegotiation = true; + if (UltraPermitted == 0) + { + SynchronousMessage = "Fast"; + CommonSynchronousNegotiation = true; + } + else if (UltraPermitted == AllTargetsMask) + { + SynchronousMessage = "Ultra"; + CommonSynchronousNegotiation = true; + } } + } if (!CommonSynchronousNegotiation) { for (TargetID = 0; @@ -2175,9 +2193,20 @@ HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->DriverScatterGatherLimit); BusLogic_Info(" Tagged Queue Depth: ", HostAdapter); - if (HostAdapter->TaggedQueueDepth > 0) - BusLogic_Info("%d", HostAdapter, HostAdapter->TaggedQueueDepth); - else BusLogic_Info("Automatic", HostAdapter); + CommonTaggedQueueDepth = true; + for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0]) + { + CommonTaggedQueueDepth = false; + break; + } + if (CommonTaggedQueueDepth) + { + if (HostAdapter->QueueDepth[0] > 0) + BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]); + else BusLogic_Info("Automatic", HostAdapter); + } + else BusLogic_Info("Individual", HostAdapter); BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter, HostAdapter->UntaggedQueueDepth); CommonErrorRecovery = true; @@ -2314,50 +2343,6 @@ /* - BusLogic_TestInterrupts tests for proper functioning of the Host Adapter - Interrupt Register and that interrupts generated by the Host Adapter are - getting through to the Interrupt Handler. A large proportion of initial - problems with installing PCI Host Adapters are due to configuration problems - where either the Host Adapter or Motherboard is configured incorrectly, and - interrupts do not get through as a result. -*/ - -static boolean BusLogic_TestInterrupts(BusLogic_HostAdapter_T *HostAdapter) -{ - unsigned int InitialInterruptCount, FinalInterruptCount; - int TestCount = 5, i; - /* - FlashPoint Host Adapters do not provide for an interrupt test. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; - /* - Inhibit the Interrupt Test if requested. - */ - if (HostAdapter->LocalOptions.Bits.InhibitInterruptTest) return true; - /* - Issue the Test Command Complete Interrupt commands. - */ - InitialInterruptCount = kstat.interrupts[HostAdapter->IRQ_Channel]; - for (i = 0; i < TestCount; i++) - BusLogic_Command(HostAdapter, BusLogic_TestCommandCompleteInterrupt, - NULL, 0, NULL, 0); - FinalInterruptCount = kstat.interrupts[HostAdapter->IRQ_Channel]; - /* - Verify that BusLogic_InterruptHandler was called at least TestCount - times. Shared IRQ Channels could cause more than TestCount interrupts to - occur, but there should never be fewer than TestCount, unless one or more - interrupts were lost. - */ - if (FinalInterruptCount < InitialInterruptCount + TestCount) - return BusLogic_Failure(HostAdapter, "HOST ADAPTER INTERRUPT TEST"); - /* - Indicate the Host Adapter Interrupt Test completed successfully. - */ - return true; -} - - -/* BusLogic_InitializeHostAdapter initializes Host Adapter. This is the only function called during SCSI Host Adapter detection which modifies the state of the Host Adapter from its initial power on or hard reset state. @@ -2376,20 +2361,31 @@ for each Target Device. */ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; - memset(HostAdapter->TaggedQueuingActive, false, - sizeof(HostAdapter->TaggedQueuingActive)); - memset(HostAdapter->CommandSuccessfulFlag, false, - sizeof(HostAdapter->CommandSuccessfulFlag)); - memset(HostAdapter->ActiveCommands, 0, - sizeof(HostAdapter->ActiveCommands)); - memset(HostAdapter->CommandsSinceReset, 0, - sizeof(HostAdapter->CommandsSinceReset)); + { + HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; + HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false; + HostAdapter->ActiveCommands[TargetID] = 0; + HostAdapter->CommandsSinceReset[TargetID] = 0; + } /* FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) goto Done; /* + Initialize the Outgoing and Incoming Mailbox pointers. + */ + HostAdapter->FirstOutgoingMailbox = + (BusLogic_OutgoingMailbox_T *) HostAdapter->MailboxSpace; + HostAdapter->LastOutgoingMailbox = + HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1; + HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; + HostAdapter->FirstIncomingMailbox = + (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1); + HostAdapter->LastIncomingMailbox = + HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; + HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; + /* Initialize the Outgoing and Incoming Mailbox structures. */ memset(HostAdapter->FirstOutgoingMailbox, 0, @@ -2397,11 +2393,6 @@ memset(HostAdapter->FirstIncomingMailbox, 0, HostAdapter->MailboxCount * sizeof(BusLogic_IncomingMailbox_T)); /* - Initialize the pointers to the Next Mailboxes. - */ - HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - /* Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes. */ ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount; @@ -2442,11 +2433,14 @@ Announce Successful Initialization. */ Done: - if (HostAdapter->HostAdapterInitialized) - BusLogic_Warning("*** %s Initialized Successfully ***\n", - HostAdapter, HostAdapter->FullModelName); - else BusLogic_Info("*** %s Initialized Successfully ***\n", - HostAdapter, HostAdapter->FullModelName); + if (!HostAdapter->HostAdapterInitialized) + { + BusLogic_Info("*** %s Initialized Successfully ***\n", + HostAdapter, HostAdapter->FullModelName); + BusLogic_Info("\n", HostAdapter); + } + else BusLogic_Warning("*** %s Initialized Successfully ***\n", + HostAdapter, HostAdapter->FullModelName); HostAdapter->HostAdapterInitialized = true; /* Indicate the Host Adapter Initialization completed successfully. @@ -2457,7 +2451,7 @@ /* BusLogic_TargetDeviceInquiry inquires about the Target Devices accessible - through Host Adapter and reports on the results. + through Host Adapter. */ static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T @@ -2468,7 +2462,7 @@ BusLogic_SetupInformation_T SetupInformation; BusLogic_SynchronousPeriod_T SynchronousPeriod; BusLogic_RequestedReplyLength_T RequestedReplyLength; - int TargetDevicesFound = 0, TargetID; + int TargetID; /* Wait a few seconds between the Host Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI Commands. Some SCSI devices get @@ -2480,13 +2474,11 @@ */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true; /* - Inhibit the Target Devices Inquiry if requested. + Inhibit the Target Device Inquiry if requested. */ - if (HostAdapter->LocalOptions.Bits.InhibitTargetInquiry) - { - BusLogic_Info(" Target Device Inquiry Inhibited\n", HostAdapter); - return true; - } + if (HostAdapter->DriverOptions != NULL && + HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) + return true; /* Issue the Inquire Target Devices command for host adapters with firmware version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command @@ -2502,6 +2494,9 @@ &InstalledDevices, sizeof(InstalledDevices)) != sizeof(InstalledDevices)) return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->TargetFlags[TargetID].TargetExists = + (InstalledDevices & (1 << TargetID) ? true : false); } else { @@ -2511,10 +2506,9 @@ != sizeof(InstalledDevicesID0to7)) return BusLogic_Failure(HostAdapter, "INQUIRE INSTALLED DEVICES ID 0 TO 7"); - InstalledDevices = 0; for (TargetID = 0; TargetID < 8; TargetID++) - if (InstalledDevicesID0to7[TargetID] != 0) - InstalledDevices |= (1 << TargetID); + HostAdapter->TargetFlags[TargetID].TargetExists = + (InstalledDevicesID0to7[TargetID] != 0 ? true : false); } /* Issue the Inquire Setup Information command. @@ -2525,6 +2519,19 @@ &SetupInformation, sizeof(SetupInformation)) != sizeof(SetupInformation)) return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->SynchronousOffset[TargetID] = + (TargetID < 8 + ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset + : SetupInformation.SynchronousValuesID8to15[TargetID-8].Offset); + if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0) + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->TargetFlags[TargetID].WideTransfersActive = + (TargetID < 8 + ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID) + ? true : false) + : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID-8)) + ? true : false)); /* Issue the Inquire Synchronous Period command. */ @@ -2536,69 +2543,96 @@ &SynchronousPeriod, sizeof(SynchronousPeriod)) != sizeof(SynchronousPeriod)) return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD"); + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID]; } else for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0) - SynchronousPeriod[TargetID] = + HostAdapter->SynchronousPeriod[TargetID] = 20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID] .TransferPeriod; - else SynchronousPeriod[TargetID] = 0; /* - Save the Installed Devices, Synchronous Values, and Synchronous Period - information in the Host Adapter structure. + Indicate the Target Device Inquiry completed successfully. + */ + return true; +} + + +/* + BusLogic_ReportTargetDeviceInfo reports about the Target Devices accessible + through Host Adapter. +*/ + +static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T + *HostAdapter) +{ + int TargetID; + /* + Inhibit the Target Device Inquiry and Reporting if requested. */ - HostAdapter->InstalledDevices = InstalledDevices; - memcpy(HostAdapter->SynchronousValues, - SetupInformation.SynchronousValuesID0to7, - sizeof(BusLogic_SynchronousValues8_T)); - if (HostAdapter->HostWideSCSI) - memcpy(&HostAdapter->SynchronousValues[8], - SetupInformation.SynchronousValuesID8to15, - sizeof(BusLogic_SynchronousValues8_T)); - memcpy(HostAdapter->SynchronousPeriod, SynchronousPeriod, - sizeof(BusLogic_SynchronousPeriod_T)); + if (BusLogic_MultiMasterHostAdapterP(HostAdapter) && + HostAdapter->DriverOptions != NULL && + HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) + return; /* Report on the Target Devices found. */ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (HostAdapter->InstalledDevices & (1 << TargetID)) - { - int SynchronousPeriod = HostAdapter->SynchronousPeriod[TargetID]; - if (SynchronousPeriod > 10) - { - int SynchronousTransferRate = 100000000 / SynchronousPeriod; - int RoundedSynchronousTransferRate = - (SynchronousTransferRate + 5000) / 10000; - BusLogic_Info(" Target %d: Synchronous at " - "%d.%02d mega-transfers/second, offset %d\n", - HostAdapter, TargetID, - RoundedSynchronousTransferRate / 100, - RoundedSynchronousTransferRate % 100, - HostAdapter->SynchronousValues[TargetID].Offset); - } - else if (SynchronousPeriod > 0) - { - int SynchronousTransferRate = 100000000 / SynchronousPeriod; - int RoundedSynchronousTransferRate = - (SynchronousTransferRate + 50000) / 100000; - BusLogic_Info(" Target %d: Synchronous at " - "%d.%01d mega-transfers/second, offset %d\n", - HostAdapter, TargetID, - RoundedSynchronousTransferRate / 10, - RoundedSynchronousTransferRate % 10, - HostAdapter->SynchronousValues[TargetID].Offset); - } - else BusLogic_Info(" Target %d: Asynchronous\n", - HostAdapter, TargetID); - TargetDevicesFound++; - } - if (TargetDevicesFound == 0) - BusLogic_Info(" No Target Devices Found\n", HostAdapter); - /* - Indicate the Target Device Inquiry completed successfully. - */ - return true; + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (TargetFlags->TargetExists && !TargetFlags->TargetInfoReported) + { + int SynchronousTransferRate = 0; + if (BusLogic_FlashPointHostAdapterP(HostAdapter)) + { + boolean WideTransfersActive; + FlashPoint_InquireTargetInfo( + HostAdapter->CardHandle, TargetID, + &HostAdapter->SynchronousPeriod[TargetID], + &HostAdapter->SynchronousOffset[TargetID], + &WideTransfersActive); + TargetFlags->WideTransfersActive = WideTransfersActive; + } + else if (TargetFlags->WideTransfersSupported && + (HostAdapter->WidePermitted & (1 << TargetID)) && + strcmp(HostAdapter->FirmwareVersion, "5.06L") < 0) + TargetFlags->WideTransfersActive = true; + if (HostAdapter->SynchronousPeriod[TargetID] > 0) + SynchronousTransferRate = + 100000 / HostAdapter->SynchronousPeriod[TargetID]; + if (TargetFlags->WideTransfersActive) + SynchronousTransferRate <<= 1; + if (SynchronousTransferRate >= 9950) + { + SynchronousTransferRate = (SynchronousTransferRate + 50) / 100; + BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at " + "%d.%01d MB/sec, offset %d\n", + HostAdapter, TargetID, + HostAdapter->QueueDepth[TargetID], + (TargetFlags->WideTransfersActive ? "Wide " : ""), + SynchronousTransferRate / 10, + SynchronousTransferRate % 10, + HostAdapter->SynchronousOffset[TargetID]); + } + else if (SynchronousTransferRate > 0) + { + SynchronousTransferRate = (SynchronousTransferRate + 5) / 10; + BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at " + "%d.%02d MB/sec, offset %d\n", + HostAdapter, TargetID, + HostAdapter->QueueDepth[TargetID], + (TargetFlags->WideTransfersActive ? "Wide " : ""), + SynchronousTransferRate / 100, + SynchronousTransferRate % 100, + HostAdapter->SynchronousOffset[TargetID]); + } + else BusLogic_Info("Target %d: Queue Depth %d, Asynchronous\n", + HostAdapter, TargetID, + HostAdapter->QueueDepth[TargetID]); + TargetFlags->TargetInfoReported = true; + } + } } @@ -2628,9 +2662,11 @@ /* - BusLogic_SelectQueueDepths selects Queue Depths for each Target Device - based on the Host Adapter's Total Queue Depth and the number, type, speed, - and capabilities of the Target Devices. + BusLogic_SelectQueueDepths selects Queue Depths for each Target Device based + on the Host Adapter's Total Queue Depth and the number, type, speed, and + capabilities of the Target Devices. When called for the last Host Adapter, + it reports on the Target Device Information for all BusLogic Host Adapters + since all the Target Devices have now been probed. */ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host, @@ -2638,41 +2674,60 @@ { BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata; - int TaggedQueueDepth = HostAdapter->TaggedQueueDepth; - int UntaggedQueueDepth = HostAdapter->UntaggedQueueDepth; - int TaggedDeviceCount = 0, UntaggedDeviceCount = 0; - int DesiredCCBs = HostAdapter->MaxTargetDevices - 1; + int TaggedDeviceCount = 0, AutomaticTaggedDeviceCount = 0; + int UntaggedDeviceCount = 0, AutomaticTaggedQueueDepth = 0; + int AllocatedQueueDepth = 0; SCSI_Device_T *Device; - for (Device = DeviceList; Device != NULL; Device = Device->next) - if (Device->host == Host) + int TargetID; + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->TargetFlags[TargetID].TargetExists) { - if (Device->tagged_supported && - (HostAdapter->TaggedQueuingPermitted & (1 << Device->id))) - TaggedDeviceCount++; + int QueueDepth = HostAdapter->UntaggedQueueDepth; + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported && + (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) + { + QueueDepth = HostAdapter->QueueDepth[TargetID]; + TaggedDeviceCount++; + if (QueueDepth == 0) AutomaticTaggedDeviceCount++; + } else UntaggedDeviceCount++; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + AllocatedQueueDepth += QueueDepth; } - if (TaggedQueueDepth == 0 && TaggedDeviceCount > 0) + HostAdapter->TargetDeviceCount = TaggedDeviceCount + UntaggedDeviceCount; + if (AutomaticTaggedDeviceCount > 0) { - TaggedQueueDepth = - 1 + ((HostAdapter->HostAdapterQueueDepth - - UntaggedDeviceCount * UntaggedQueueDepth) - / TaggedDeviceCount); - if (TaggedQueueDepth > BusLogic_PreferredTaggedQueueDepth) - TaggedQueueDepth = BusLogic_PreferredTaggedQueueDepth; - } - for (Device = DeviceList; Device != NULL; Device = Device->next) + AutomaticTaggedQueueDepth = + (HostAdapter->HostAdapterQueueDepth - AllocatedQueueDepth) + / AutomaticTaggedDeviceCount; + if (AutomaticTaggedQueueDepth > BusLogic_MaxAutomaticTaggedQueueDepth) + AutomaticTaggedQueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth; + if (AutomaticTaggedQueueDepth < BusLogic_MinAutomaticTaggedQueueDepth) + AutomaticTaggedQueueDepth = BusLogic_MinAutomaticTaggedQueueDepth; + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->TargetFlags[TargetID].TargetExists && + HostAdapter->QueueDepth[TargetID] == 0) + { + AllocatedQueueDepth += AutomaticTaggedQueueDepth; + HostAdapter->QueueDepth[TargetID] = AutomaticTaggedQueueDepth; + } + } + for (Device = DeviceList; Device != NULL; Device = Device->next) if (Device->host == Host) - { - if (Device->tagged_supported && - (HostAdapter->TaggedQueuingPermitted & (1 << Device->id))) - Device->queue_depth = TaggedQueueDepth; - else Device->queue_depth = UntaggedQueueDepth; - HostAdapter->QueueDepth[Device->id] = Device->queue_depth; - DesiredCCBs += Device->queue_depth; - } + Device->queue_depth = HostAdapter->QueueDepth[Device->id]; + /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */ + AllocatedQueueDepth += HostAdapter->TargetDeviceCount; + if (AllocatedQueueDepth > HostAdapter->DriverQueueDepth) + AllocatedQueueDepth = HostAdapter->DriverQueueDepth; BusLogic_CreateAdditionalCCBs(HostAdapter, - DesiredCCBs - HostAdapter->AllocatedCCBs, + AllocatedQueueDepth + - HostAdapter->AllocatedCCBs, false); + if (HostAdapter == BusLogic_LastRegisteredHostAdapter) + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; + HostAdapter != NULL; + HostAdapter = HostAdapter->NextAll) + BusLogic_ReportTargetDeviceInfo(HostAdapter); } @@ -2686,50 +2741,48 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate) { - int BusLogicHostAdapterCount = 0, CommandLineEntryIndex = 0, ProbeIndex; - char *MessageBuffer = NULL; - if (BusLogic_ProbeOptions.Bits.NoProbe) return 0; - BusLogic_InitializeProbeInfoList(); + int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex; + BusLogic_HostAdapter_T *PrototypeHostAdapter; + if (BusLogic_ProbeOptions.NoProbe) return 0; + BusLogic_ProbeInfoList = (BusLogic_ProbeInfo_T *) + kmalloc(BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T), + GFP_ATOMIC); + if (BusLogic_ProbeInfoList == NULL) + { + BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL); + return 0; + } + memset(BusLogic_ProbeInfoList, 0, + BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T)); + PrototypeHostAdapter = (BusLogic_HostAdapter_T *) + kmalloc(sizeof(BusLogic_HostAdapter_T), GFP_ATOMIC); + if (PrototypeHostAdapter == NULL) + { + kfree(BusLogic_ProbeInfoList); + BusLogic_Error("BusLogic: Unable to allocate Prototype " + "Host Adapter\n", NULL); + return 0; + } + memset(PrototypeHostAdapter, 0, sizeof(BusLogic_HostAdapter_T)); + if (BusLogic_Options != NULL) + BusLogic_ParseDriverOptions(BusLogic_Options); + BusLogic_InitializeProbeInfoList(PrototypeHostAdapter); for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++) { BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex]; - BusLogic_HostAdapter_T HostAdapterPrototype; - BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype; + BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter; SCSI_Host_T *Host; if (ProbeInfo->IO_Address == 0) continue; memset(HostAdapter, 0, sizeof(BusLogic_HostAdapter_T)); - HostAdapter->IO_Address = ProbeInfo->IO_Address; - HostAdapter->PCI_Address = ProbeInfo->PCI_Address; HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType; HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType; + HostAdapter->IO_Address = ProbeInfo->IO_Address; + HostAdapter->PCI_Address = ProbeInfo->PCI_Address; HostAdapter->Bus = ProbeInfo->Bus; HostAdapter->Device = ProbeInfo->Device; HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel; HostAdapter->AddressCount = - BusLogic_HostAdapter_AddressCount[HostAdapter->HostAdapterType]; - if (MessageBuffer == NULL) - MessageBuffer = - scsi_init_malloc(BusLogic_MessageBufferSize, GFP_ATOMIC); - if (MessageBuffer == NULL) - { - BusLogic_Error("BusLogic: Unable to allocate Message Buffer\n", - HostAdapter); - return BusLogicHostAdapterCount; - } - HostAdapter->MessageBuffer = MessageBuffer; - /* - If an explicit I/O Address was specified, Initialize the Command Line - Entry field and inhibit the check for whether the I/O Address range is - already in use. - */ - if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount && - BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address == - HostAdapter->IO_Address) - HostAdapter->CommandLineEntry = - &BusLogic_CommandLineEntries[CommandLineEntryIndex++]; - else if (check_region(HostAdapter->IO_Address, - HostAdapter->AddressCount) < 0) - continue; + BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType]; /* Probe the Host Adapter. If unsuccessful, abort further initialization. */ @@ -2738,22 +2791,20 @@ Hard Reset the Host Adapter. If unsuccessful, abort further initialization. */ - if (!BusLogic_HardResetHostAdapter(HostAdapter)) continue; + if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) continue; /* Check the Host Adapter. If unsuccessful, abort further initialization. */ if (!BusLogic_CheckHostAdapter(HostAdapter)) continue; /* - Initialize the Command Line Entry field if an explicit I/O Address - was not specified. + Initialize the Driver Options field if provided. */ - if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount && - BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address == 0) - HostAdapter->CommandLineEntry = - &BusLogic_CommandLineEntries[CommandLineEntryIndex++]; + if (DriverOptionsIndex < BusLogic_DriverOptionsCount) + HostAdapter->DriverOptions = + &BusLogic_DriverOptions[DriverOptionsIndex++]; /* Announce the Driver Version and Date, Author's Name, Copyright Notice, - and Contact Address. + and Electronic Mail Address. */ BusLogic_AnnounceDriver(HostAdapter); /* @@ -2771,8 +2822,7 @@ */ Host = scsi_register(HostTemplate, sizeof(BusLogic_HostAdapter_T)); HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata; - memcpy(HostAdapter, &HostAdapterPrototype, - sizeof(BusLogic_HostAdapter_T)); + memcpy(HostAdapter, PrototypeHostAdapter, sizeof(BusLogic_HostAdapter_T)); HostAdapter->SCSI_Host = Host; HostAdapter->HostNumber = Host->host_no; Host->select_queue_depths = BusLogic_SelectQueueDepths; @@ -2785,18 +2835,14 @@ BusLogic_RegisterHostAdapter(HostAdapter); /* Read the Host Adapter Configuration, Configure the Host Adapter, - Acquire the System Resources necessary to use the Host Adapter, - then Test Interrupts, Create the Mailboxes, Initial CCBs, and - Target Device Statistics, Initialize the Host Adapter, and - finally perform Target Device Inquiry. + Acquire the System Resources necessary to use the Host Adapter, then + Create the Initial CCBs, Initialize the Host Adapter, and finally + perform Target Device Inquiry. */ if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && BusLogic_ReportHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && - BusLogic_TestInterrupts(HostAdapter) && - BusLogic_CreateMailboxes(HostAdapter) && BusLogic_CreateInitialCCBs(HostAdapter) && - BusLogic_CreateTargetDeviceStatistics(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && BusLogic_TargetDeviceInquiry(HostAdapter)) { @@ -2806,7 +2852,6 @@ Name of the Host Adapter will appear, and initialize the SCSI Host structure. */ - MessageBuffer = NULL; release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); request_region(HostAdapter->IO_Address, @@ -2818,24 +2863,22 @@ else { /* - An error occurred during Host Adapter Configuration Querying, - Host Adapter Configuration, Resource Acquisition, Interrupt - Testing, CCB Creation, Host Adapter Initialization, or Target - Device Inquiry, so remove Host Adapter from the list of - registered BusLogic Host Adapters, destroy the Target Device - Statistics, CCBs, and Mailboxes, Release the System Resources, - and Unregister the SCSI Host. + An error occurred during Host Adapter Configuration Querying, Host + Adapter Configuration, Resource Acquisition, CCB Creation, Host + Adapter Initialization, or Target Device Inquiry, so remove Host + Adapter from the list of registered BusLogic Host Adapters, destroy + the CCBs, Release the System Resources, and Unregister the SCSI + Host. */ - BusLogic_DestroyTargetDeviceStatistics(HostAdapter); BusLogic_DestroyCCBs(HostAdapter); - BusLogic_DestroyMailboxes(HostAdapter); BusLogic_ReleaseResources(HostAdapter); BusLogic_UnregisterHostAdapter(HostAdapter); scsi_unregister(Host); } } - if (MessageBuffer != NULL) - scsi_init_free(MessageBuffer, BusLogic_MessageBufferSize); + kfree(PrototypeHostAdapter); + kfree(BusLogic_ProbeInfoList); + BusLogic_ProbeInfoList = NULL; return BusLogicHostAdapterCount; } @@ -2851,21 +2894,16 @@ BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata; /* - FlashPoint Host Adapters must also be released by the FlashPoint + FlashPoint Host Adapters must first be released by the FlashPoint SCCB Manager. */ if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - { - FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle); - scsi_init_free((char *) HostAdapter->FlashPointInfo, - sizeof(FlashPoint_Info_T)); - } + FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle); /* - Destroy the CCBs and Mailboxes, and release any system resources acquired - to support Host Adapter. + Destroy the CCBs and release any system resources acquired to + support Host Adapter. */ BusLogic_DestroyCCBs(HostAdapter); - BusLogic_DestroyMailboxes(HostAdapter); BusLogic_ReleaseResources(HostAdapter); /* Release usage of the I/O Address range. @@ -2988,27 +3026,29 @@ BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) Bus_to_Virtual(NextIncomingMailbox->CCB); if (CompletionCode != BusLogic_AbortedCommandNotFound) - if (CCB->Status == BusLogic_CCB_Active || - CCB->Status == BusLogic_CCB_Reset) - { - /* - Save the Completion Code for this CCB and queue the CCB - for completion processing. - */ - CCB->CompletionCode = CompletionCode; - BusLogic_QueueCompletedCCB(CCB); - } - else - { - /* - If a CCB ever appears in an Incoming Mailbox and is not marked as - status Active or Reset, then there is most likely a bug in the - Host Adapter firmware. - */ - BusLogic_Warning("Illegal CCB #%ld status %d in " - "Incoming Mailbox\n", HostAdapter, - CCB->SerialNumber, CCB->Status); - } + { + if (CCB->Status == BusLogic_CCB_Active || + CCB->Status == BusLogic_CCB_Reset) + { + /* + Save the Completion Code for this CCB and queue the CCB + for completion processing. + */ + CCB->CompletionCode = CompletionCode; + BusLogic_QueueCompletedCCB(CCB); + } + else + { + /* + If a CCB ever appears in an Incoming Mailbox and is not marked + as status Active or Reset, then there is most likely a bug in + the Host Adapter firmware. + */ + BusLogic_Warning("Illegal CCB #%ld status %d in " + "Incoming Mailbox\n", HostAdapter, + CCB->SerialNumber, CCB->Status); + } + } NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree; if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox) NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; @@ -3047,10 +3087,9 @@ "%d Completed\n", HostAdapter, CCB->SerialNumber, TargetID); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID] - .BusDeviceResetsCompleted); + &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted); + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; HostAdapter->CommandsSinceReset[TargetID] = 0; - HostAdapter->TaggedQueuingActive[TargetID] = false; HostAdapter->LastResetCompleted[TargetID] = jiffies; /* Place CCB back on the Host Adapter's free list. @@ -3101,16 +3140,17 @@ HostAdapter, CCB->SerialNumber, CCB->TargetID); break; case BusLogic_CommandCompletedWithoutError: - HostAdapter->TargetDeviceStatistics[CCB->TargetID] + HostAdapter->TargetStatistics[CCB->TargetID] .CommandsCompleted++; - HostAdapter->CommandSuccessfulFlag[CCB->TargetID] = true; + HostAdapter->TargetFlags[CCB->TargetID] + .CommandSuccessfulFlag = true; Command->result = DID_OK << 16; break; case BusLogic_CommandAbortedAtHostRequest: BusLogic_Warning("CCB #%ld to Target %d Aborted\n", HostAdapter, CCB->SerialNumber, CCB->TargetID); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[CCB->TargetID] + &HostAdapter->TargetStatistics[CCB->TargetID] .CommandAbortsCompleted); Command->result = DID_ABORT << 16; break; @@ -3121,9 +3161,9 @@ CCB->TargetDeviceStatus); if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) { - HostAdapter->TargetDeviceStatistics[CCB->TargetID] + HostAdapter->TargetStatistics[CCB->TargetID] .CommandsCompleted++; - if (BusLogic_GlobalOptions.Bits.TraceErrors) + if (BusLogic_GlobalOptions.TraceErrors) { int i; BusLogic_Notice("CCB #%ld Target %d: Result %X Host " @@ -3147,6 +3187,22 @@ break; } /* + When an INQUIRY command completes normally, save the + CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit + Wide Data Transfers Supported) bits. + */ + if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && + CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) + { + BusLogic_TargetFlags_T *TargetFlags = + &HostAdapter->TargetFlags[CCB->TargetID]; + SCSI_Inquiry_T *InquiryResult = + (SCSI_Inquiry_T *) Command->request_buffer; + TargetFlags->TargetExists = true; + TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue; + TargetFlags->WideTransfersSupported = InquiryResult->WBus16; + } + /* Place CCB back on the Host Adapter's free list. */ BusLogic_DeallocateCCB(CCB); @@ -3171,7 +3227,7 @@ { BusLogic_HostAdapter_T *FirstHostAdapter = BusLogic_RegisteredHostAdapters[IRQ_Channel]; - boolean HostAdapterResetRequested = false; + boolean HostAdapterResetRequired = false; BusLogic_HostAdapter_T *HostAdapter; BusLogic_Lock_T Lock; /* @@ -3213,8 +3269,8 @@ */ if (InterruptRegister.Bits.ExternalBusReset) { - HostAdapter->HostAdapterResetRequested = true; - HostAdapterResetRequested = true; + HostAdapter->HostAdapterExternalReset = true; + HostAdapterResetRequired = true; } else if (InterruptRegister.Bits.IncomingMailboxLoaded) BusLogic_ScanIncomingMailboxes(HostAdapter); @@ -3228,11 +3284,20 @@ Check if there is a pending interrupt for this Host Adapter. */ if (FlashPoint_InterruptPending(HostAdapter->CardHandle)) - if (FlashPoint_HandleInterrupt(HostAdapter->CardHandle) - == FlashPoint_ExternalBusReset) + switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)) { - HostAdapter->HostAdapterResetRequested = true; - HostAdapterResetRequested = true; + case FlashPoint_NormalInterrupt: + break; + case FlashPoint_ExternalBusReset: + HostAdapter->HostAdapterExternalReset = true; + HostAdapterResetRequired = true; + break; + case FlashPoint_InternalError: + BusLogic_Warning("Internal FlashPoint Error detected" + " - Resetting Host Adapter\n", HostAdapter); + HostAdapter->HostAdapterInternalError = true; + HostAdapterResetRequired = true; + break; } } /* @@ -3249,14 +3314,16 @@ Iterate over the Host Adapters performing any requested Host Adapter Resets. */ - if (HostAdapterResetRequested) + if (HostAdapterResetRequired) for (HostAdapter = FirstHostAdapter; HostAdapter != NULL; HostAdapter = HostAdapter->Next) - if (HostAdapter->HostAdapterResetRequested) + if (HostAdapter->HostAdapterExternalReset || + HostAdapter->HostAdapterInternalError) { BusLogic_ResetHostAdapter(HostAdapter, NULL, 0); - HostAdapter->HostAdapterResetRequested = false; + HostAdapter->HostAdapterExternalReset = false; + HostAdapter->HostAdapterInternalError = false; scsi_mark_host_reset(HostAdapter->SCSI_Host); } } @@ -3293,8 +3360,7 @@ { HostAdapter->ActiveCommands[CCB->TargetID]++; if (CCB->Opcode != BusLogic_BusDeviceReset) - HostAdapter->TargetDeviceStatistics[CCB->TargetID] - .CommandsAttempted++; + HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++; } return true; } @@ -3312,8 +3378,10 @@ { BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Command->host->hostdata; - BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics = - HostAdapter->TargetDeviceStatistics; + BusLogic_TargetFlags_T *TargetFlags = + &HostAdapter->TargetFlags[Command->target]; + BusLogic_TargetStatistics_T *TargetStatistics = + HostAdapter->TargetStatistics; unsigned char *CDB = Command->cmnd; int CDB_Length = Command->cmd_len; int TargetID = Command->target; @@ -3371,13 +3439,9 @@ int Segment; CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T); -#ifndef CONFIG_SCSI_OMIT_FLASHPOINT if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList); - else CCB->DataPointer = (BusLogic_BusAddress_T) CCB->ScatterGatherList; -#else - CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList); -#endif + else CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList); for (Segment = 0; Segment < SegmentCount; Segment++) { CCB->ScatterGatherList[Segment].SegmentByteCount = @@ -3391,22 +3455,20 @@ case READ_6: case READ_10: CCB->DataDirection = BusLogic_DataInLengthChecked; - TargetDeviceStatistics[TargetID].ReadCommands++; + TargetStatistics[TargetID].ReadCommands++; BusLogic_IncrementByteCounter( - &TargetDeviceStatistics[TargetID].TotalBytesRead, BufferLength); + &TargetStatistics[TargetID].TotalBytesRead, BufferLength); BusLogic_IncrementSizeBucket( - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets, - BufferLength); + TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength); break; case WRITE_6: case WRITE_10: CCB->DataDirection = BusLogic_DataOutLengthChecked; - TargetDeviceStatistics[TargetID].WriteCommands++; + TargetStatistics[TargetID].WriteCommands++; BusLogic_IncrementByteCounter( - &TargetDeviceStatistics[TargetID].TotalBytesWritten, BufferLength); + &TargetStatistics[TargetID].TotalBytesWritten, BufferLength); BusLogic_IncrementSizeBucket( - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets, - BufferLength); + TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength); break; default: CCB->DataDirection = BusLogic_UncheckedDataTransfer; @@ -3434,20 +3496,18 @@ necessary to wait until there are no pending commands for a target device before queuing tagged commands. */ - HostAdapter->TaggedQueuingSupported[TargetID] = - Command->device->tagged_supported; if (HostAdapter->CommandsSinceReset[TargetID]++ >= BusLogic_MaxTaggedQueueDepth && - !HostAdapter->TaggedQueuingActive[TargetID] && + !TargetFlags->TaggedQueuingActive && HostAdapter->ActiveCommands[TargetID] == 0 && - HostAdapter->TaggedQueuingSupported[TargetID] && + TargetFlags->TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) { - HostAdapter->TaggedQueuingActive[TargetID] = true; + TargetFlags->TaggedQueuingActive = true; BusLogic_Notice("Tagged Queuing now active for Target %d\n", HostAdapter, TargetID); } - if (HostAdapter->TaggedQueuingActive[TargetID]) + if (TargetFlags->TaggedQueuingActive) { BusLogic_QueueTag_T QueueTag = BusLogic_SimpleQueueTag; /* @@ -3457,7 +3517,7 @@ write nearer the head position continue to arrive without interruption. Therefore, for each Target Device this driver keeps track of the last time either the queue was empty or an Ordered Queue Tag was issued. If - more than 3 seconds (one fifth of the 15 second disk timeout) have + more than 4 seconds (one fifth of the 20 second disk timeout) have elapsed since this last sequence point, this command will be issued with an Ordered Queue Tag rather than a Simple Queue Tag, which forces the Target Device to complete all previously queued commands before @@ -3465,7 +3525,7 @@ */ if (HostAdapter->ActiveCommands[TargetID] == 0) HostAdapter->LastSequencePoint[TargetID] = jiffies; - else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 3*HZ) + else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4*HZ) { HostAdapter->LastSequencePoint[TargetID] = jiffies; QueueTag = BusLogic_OrderedQueueTag; @@ -3519,7 +3579,7 @@ */ CCB->Status = BusLogic_CCB_Active; HostAdapter->ActiveCommands[TargetID]++; - TargetDeviceStatistics[TargetID].CommandsAttempted++; + TargetStatistics[TargetID].CommandsAttempted++; FlashPoint_StartCCB(HostAdapter->CardHandle, CCB); /* The Command may have already completed and BusLogic_QueueCompletedCCB @@ -3550,7 +3610,7 @@ BusLogic_CCB_T *CCB; int Result; BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsRequested); + &HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested); /* Acquire exclusive access to Host Adapter. */ @@ -3604,7 +3664,7 @@ Firmware version 5.xx does generate Abort Tag messages, so it is possible to abort commands when Tagged Queuing is active. */ - if (HostAdapter->TaggedQueuingActive[TargetID] && + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && HostAdapter->FirmwareVersion[0] < '5') { BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " @@ -3618,8 +3678,7 @@ BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID] - .CommandAbortsAttempted); + &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); Result = SCSI_ABORT_PENDING; } else @@ -3638,7 +3697,7 @@ BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsAttempted); + &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB); /* The Abort may have already been completed and @@ -3673,11 +3732,24 @@ BusLogic_Lock_T Lock; BusLogic_CCB_T *CCB; int TargetID, Result; - if (Command == NULL) - BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets); - else BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[Command->target] - .HostAdapterResetsRequested); + boolean HardReset; + if (HostAdapter->HostAdapterExternalReset) + { + BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets); + HardReset = false; + } + else if (HostAdapter->HostAdapterInternalError) + { + BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors); + HardReset = true; + } + else + { + BusLogic_IncrementErrorCounter( + &HostAdapter->TargetStatistics[Command->target] + .HostAdapterResetsRequested); + HardReset = true; + } /* Acquire exclusive access to Host Adapter. */ @@ -3723,20 +3795,25 @@ } } if (Command == NULL) - BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", - HostAdapter, HostAdapter->FullModelName); + { + if (HostAdapter->HostAdapterInternalError) + BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n", + HostAdapter, HostAdapter->FullModelName); + else BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", + HostAdapter, HostAdapter->FullModelName); + } else { BusLogic_Warning("Resetting %s due to Target %d\n", HostAdapter, HostAdapter->FullModelName, Command->target); BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[Command->target] + &HostAdapter->TargetStatistics[Command->target] .HostAdapterResetsAttempted); } /* Attempt to Reset and Reinitialize the Host Adapter. */ - if (!(BusLogic_HardResetHostAdapter(HostAdapter) && + if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) && BusLogic_InitializeHostAdapter(HostAdapter))) { BusLogic_Error("Resetting %s Failed\n", HostAdapter, @@ -3746,7 +3823,7 @@ } if (Command != NULL) BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[Command->target] + &HostAdapter->TargetStatistics[Command->target] .HostAdapterResetsCompleted); /* Mark all currently executing CCBs as having been Reset. @@ -3761,7 +3838,8 @@ Note that a timer interrupt may occur here, but all active CCBs have already been marked Reset and so a reentrant call will return Pending. */ - BusLogic_Delay(HostAdapter->BusSettleTime); + if (HardReset) + BusLogic_Delay(HostAdapter->BusSettleTime); /* If this is a Synchronous Reset, perform completion processing for the Command being Reset. @@ -3817,7 +3895,7 @@ BusLogic_Lock_T Lock; int Result = -1; BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsRequested); + &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsRequested); /* Acquire exclusive access to Host Adapter. */ @@ -3891,7 +3969,7 @@ while there are tagged commands outstanding. Therefore, in that case a full Host Adapter Hard Reset and SCSI Bus Reset must be done. */ - if (HostAdapter->TaggedQueuingActive[TargetID] && + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && HostAdapter->ActiveCommands[TargetID] > 0 && HostAdapter->FirmwareVersion[0] < '5') goto Done; @@ -3958,7 +4036,7 @@ processing performed. */ BusLogic_IncrementErrorCounter( - &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted); + &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsAttempted); HostAdapter->BusDeviceResetPendingCCB[TargetID] = CCB; HostAdapter->LastResetAttempted[TargetID] = jiffies; for (XCCB = HostAdapter->All_CCBs; XCCB != NULL; XCCB = XCCB->NextAll) @@ -4007,11 +4085,11 @@ it has been less than 10 minutes since the last reset occurred, or since the system was initialized if no prior resets have occurred. */ - if (HostAdapter->TaggedQueuingActive[TargetID] && + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && jiffies - HostAdapter->LastResetCompleted[TargetID] < 10*60*HZ) { HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID); - HostAdapter->TaggedQueuingActive[TargetID] = false; + HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; BusLogic_Warning("Tagged Queuing now disabled for Target %d\n", HostAdapter, TargetID); } @@ -4032,10 +4110,10 @@ forcing a Hard Reset before the Bus Device Reset has had a chance to clear the error condition. */ - if (HostAdapter->CommandSuccessfulFlag[TargetID] || + if (HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag || jiffies - HostAdapter->LastResetAttempted[TargetID] < HZ/10) { - HostAdapter->CommandSuccessfulFlag[TargetID] = false; + HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false; return BusLogic_SendBusDeviceReset(HostAdapter, Command, ResetFlags); } /* Fall through to Hard Reset case. */ @@ -4076,16 +4154,18 @@ struct buffer_head *BufferHead; if (HostAdapter->ExtendedTranslationEnabled && Disk->capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */) - if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */) - { - DiskParameters->Heads = 255; - DiskParameters->Sectors = 63; - } - else - { - DiskParameters->Heads = 128; - DiskParameters->Sectors = 32; - } + { + if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */) + { + DiskParameters->Heads = 255; + DiskParameters->Sectors = 63; + } + else + { + DiskParameters->Heads = 128; + DiskParameters->Sectors = 32; + } + } else { DiskParameters->Heads = 64; @@ -4105,24 +4185,28 @@ */ if (*(unsigned short *) (BufferHead->b_data + 0x1FE) == 0xAA55) { - struct partition *PartitionEntry = - (struct partition *) (BufferHead->b_data + 0x1BE); + PartitionTable_T *FirstPartitionEntry = + (PartitionTable_T *) (BufferHead->b_data + 0x1BE); + PartitionTable_T *PartitionEntry = FirstPartitionEntry; int SavedCylinders = DiskParameters->Cylinders, PartitionNumber; + unsigned char PartitionEntryEndHead, PartitionEntryEndSector; for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++) { - if (PartitionEntry->end_head == 64-1) + PartitionEntryEndHead = PartitionEntry->end_head; + PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F; + if (PartitionEntryEndHead == 64-1) { DiskParameters->Heads = 64; DiskParameters->Sectors = 32; break; } - else if (PartitionEntry->end_head == 128-1) + else if (PartitionEntryEndHead == 128-1) { DiskParameters->Heads = 128; DiskParameters->Sectors = 32; break; } - else if (PartitionEntry->end_head == 255-1) + else if (PartitionEntryEndHead == 255-1) { DiskParameters->Heads = 255; DiskParameters->Sectors = 63; @@ -4130,14 +4214,29 @@ } PartitionEntry++; } + if (PartitionNumber == 4) + { + PartitionEntryEndHead = FirstPartitionEntry->end_head; + PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F; + } DiskParameters->Cylinders = Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors); - if (SavedCylinders != DiskParameters->Cylinders) + if (PartitionNumber < 4 && + PartitionEntryEndSector == DiskParameters->Sectors) { - BusLogic_Warning("Warning: Extended Translation Setting " - "(> 1GB Switch) does not match\n", HostAdapter); - BusLogic_Warning("Partition Table - Adopting %d/%d Geometry " - "from Partition Table\n", HostAdapter, + if (DiskParameters->Cylinders != SavedCylinders) + BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n", + HostAdapter, + DiskParameters->Heads, DiskParameters->Sectors); + } + else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0) + { + BusLogic_Warning("Warning: Partition Table appears to " + "have Geometry %d/%d which is\n", HostAdapter, + PartitionEntryEndHead + 1, + PartitionEntryEndSector); + BusLogic_Warning("not compatible with current BusLogic " + "Host Adapter Geometry %d/%d\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors); } } @@ -4155,22 +4254,21 @@ int HostNumber, int WriteFlag) { BusLogic_HostAdapter_T *HostAdapter; - BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics; - int IRQ_Channel, TargetID, Length; + BusLogic_TargetStatistics_T *TargetStatistics; + int TargetID, Length; char *Buffer; if (WriteFlag) return 0; - for (IRQ_Channel = 0; IRQ_Channel < NR_IRQS; IRQ_Channel++) + for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; + HostAdapter != NULL; + HostAdapter = HostAdapter->NextAll) + if (HostAdapter->HostNumber == HostNumber) break; + if (HostAdapter == NULL) { - HostAdapter = BusLogic_RegisteredHostAdapters[IRQ_Channel]; - while (HostAdapter != NULL) - { - if (HostAdapter->HostNumber == HostNumber) break; - HostAdapter = HostAdapter->Next; - } - if (HostAdapter != NULL) break; + BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n", + NULL, HostNumber); + return 0; } - if (HostAdapter == NULL) return -1; - TargetDeviceStatistics = HostAdapter->TargetDeviceStatistics; + TargetStatistics = HostAdapter->TargetStatistics; Buffer = HostAdapter->MessageBuffer; Length = HostAdapter->MessageBufferLength; Length += sprintf(&Buffer[Length], "\n\ @@ -4181,100 +4279,105 @@ Length += sprintf(&Buffer[Length], "\n\n\ DATA TRANSFER STATISTICS\n\ \n\ -Target Tagged Queuing Queue Depth Commands Attempted Commands Completed\n\ -====== ============== =========== ================== ==================\n"); +Target Tagged Queuing Queue Depth Active Attempted Completed\n\ +====== ============== =========== ====== ========= =========\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) - { - Length += - sprintf(&Buffer[Length], " %2d %s", TargetID, - (HostAdapter->TaggedQueuingSupported[TargetID] - ? (HostAdapter->TaggedQueuingActive[TargetID] - ? " Active" - : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID) - ? " Permitted" : " Disabled")) - : "Not Supported")); - Length += sprintf(&Buffer[Length], - " %3d %9u %9u\n", - HostAdapter->QueueDepth[TargetID], - TargetDeviceStatistics[TargetID].CommandsAttempted, - TargetDeviceStatistics[TargetID].CommandsCompleted); - } + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; + Length += + sprintf(&Buffer[Length], " %2d %s", TargetID, + (TargetFlags->TaggedQueuingSupported + ? (TargetFlags->TaggedQueuingActive + ? " Active" + : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID) + ? " Permitted" : " Disabled")) + : "Not Supported")); + Length += sprintf(&Buffer[Length], + " %3d %3u %9u %9u\n", + HostAdapter->QueueDepth[TargetID], + HostAdapter->ActiveCommands[TargetID], + TargetStatistics[TargetID].CommandsAttempted, + TargetStatistics[TargetID].CommandsCompleted); + } Length += sprintf(&Buffer[Length], "\n\ Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\ ====== ============= ============== =================== ===================\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) - { + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; + Length += + sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, + TargetStatistics[TargetID].ReadCommands, + TargetStatistics[TargetID].WriteCommands); + if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0) Length += - sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, - TargetDeviceStatistics[TargetID].ReadCommands, - TargetDeviceStatistics[TargetID].WriteCommands); - if (TargetDeviceStatistics[TargetID].TotalBytesRead.Billions > 0) - Length += - sprintf(&Buffer[Length], " %9u%09u", - TargetDeviceStatistics[TargetID].TotalBytesRead.Billions, - TargetDeviceStatistics[TargetID].TotalBytesRead.Units); - else - Length += - sprintf(&Buffer[Length], " %9u", - TargetDeviceStatistics[TargetID].TotalBytesRead.Units); - if (TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions > 0) - Length += - sprintf(&Buffer[Length], " %9u%09u\n", - TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions, - TargetDeviceStatistics[TargetID].TotalBytesWritten.Units); - else - Length += - sprintf(&Buffer[Length], " %9u\n", - TargetDeviceStatistics[TargetID].TotalBytesWritten.Units); - } + sprintf(&Buffer[Length], " %9u%09u", + TargetStatistics[TargetID].TotalBytesRead.Billions, + TargetStatistics[TargetID].TotalBytesRead.Units); + else + Length += + sprintf(&Buffer[Length], " %9u", + TargetStatistics[TargetID].TotalBytesRead.Units); + if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0) + Length += + sprintf(&Buffer[Length], " %9u%09u\n", + TargetStatistics[TargetID].TotalBytesWritten.Billions, + TargetStatistics[TargetID].TotalBytesWritten.Units); + else + Length += + sprintf(&Buffer[Length], " %9u\n", + TargetStatistics[TargetID].TotalBytesWritten.Units); + } Length += sprintf(&Buffer[Length], "\n\ Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\ ====== ======= ========= ========= ========= ========= =========\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) - { - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[0], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[1], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[2], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[3], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[4]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[0], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[1], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[2], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[3], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[4]); - } + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; + Length += + sprintf(&Buffer[Length], + " %2d Read %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].ReadCommandSizeBuckets[0], + TargetStatistics[TargetID].ReadCommandSizeBuckets[1], + TargetStatistics[TargetID].ReadCommandSizeBuckets[2], + TargetStatistics[TargetID].ReadCommandSizeBuckets[3], + TargetStatistics[TargetID].ReadCommandSizeBuckets[4]); + Length += + sprintf(&Buffer[Length], + " %2d Write %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].WriteCommandSizeBuckets[0], + TargetStatistics[TargetID].WriteCommandSizeBuckets[1], + TargetStatistics[TargetID].WriteCommandSizeBuckets[2], + TargetStatistics[TargetID].WriteCommandSizeBuckets[3], + TargetStatistics[TargetID].WriteCommandSizeBuckets[4]); + } Length += sprintf(&Buffer[Length], "\n\ Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\ ====== ======= ========= ========= ========= ========= =========\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) - { - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[5], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[6], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[7], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[8], - TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[9]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[5], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[6], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[7], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[8], - TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[9]); - } + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; + Length += + sprintf(&Buffer[Length], + " %2d Read %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].ReadCommandSizeBuckets[5], + TargetStatistics[TargetID].ReadCommandSizeBuckets[6], + TargetStatistics[TargetID].ReadCommandSizeBuckets[7], + TargetStatistics[TargetID].ReadCommandSizeBuckets[8], + TargetStatistics[TargetID].ReadCommandSizeBuckets[9]); + Length += + sprintf(&Buffer[Length], + " %2d Write %9u %9u %9u %9u %9u\n", TargetID, + TargetStatistics[TargetID].WriteCommandSizeBuckets[5], + TargetStatistics[TargetID].WriteCommandSizeBuckets[6], + TargetStatistics[TargetID].WriteCommandSizeBuckets[7], + TargetStatistics[TargetID].WriteCommandSizeBuckets[8], + TargetStatistics[TargetID].WriteCommandSizeBuckets[9]); + } Length += sprintf(&Buffer[Length], "\n\n\ ERROR RECOVERY STATISTICS\n\ \n\ @@ -4283,21 +4386,26 @@ ID \\\\\\\\ Attempted //// \\\\\\\\ Attempted //// \\\\\\\\ Attempted ////\n\ ====== ===== ===== ===== ===== ===== ===== ===== ===== =====\n"); for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0) + { + BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; + if (!TargetFlags->TargetExists) continue; Length += sprintf(&Buffer[Length], "\ %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", TargetID, - TargetDeviceStatistics[TargetID].CommandAbortsRequested, - TargetDeviceStatistics[TargetID].CommandAbortsAttempted, - TargetDeviceStatistics[TargetID].CommandAbortsCompleted, - TargetDeviceStatistics[TargetID].BusDeviceResetsRequested, - TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted, - TargetDeviceStatistics[TargetID].BusDeviceResetsCompleted, - TargetDeviceStatistics[TargetID].HostAdapterResetsRequested, - TargetDeviceStatistics[TargetID].HostAdapterResetsAttempted, - TargetDeviceStatistics[TargetID].HostAdapterResetsCompleted); + TargetStatistics[TargetID].CommandAbortsRequested, + TargetStatistics[TargetID].CommandAbortsAttempted, + TargetStatistics[TargetID].CommandAbortsCompleted, + TargetStatistics[TargetID].BusDeviceResetsRequested, + TargetStatistics[TargetID].BusDeviceResetsAttempted, + TargetStatistics[TargetID].BusDeviceResetsCompleted, + TargetStatistics[TargetID].HostAdapterResetsRequested, + TargetStatistics[TargetID].HostAdapterResetsAttempted, + TargetStatistics[TargetID].HostAdapterResetsCompleted); + } Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n", HostAdapter->ExternalHostAdapterResets); + Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n", + HostAdapter->HostAdapterInternalErrors); if (Length >= BusLogic_MessageBufferSize) BusLogic_Error("Message Buffer length %d exceeds size %d\n", HostAdapter, Length, BusLogic_MessageBufferSize); @@ -4339,17 +4447,22 @@ Buffer); HostAdapter->MessageBufferLength += Length; if (BeginningOfLine) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], - HostAdapter->HostNumber, Buffer); + { + if (Buffer[0] != '\n' || Length > 1) + printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], + HostAdapter->HostNumber, Buffer); + } else printk("%s", Buffer); } else { if (BeginningOfLine) - if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], - HostAdapter->HostNumber, Buffer); - else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer); + { + if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized) + printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], + HostAdapter->HostNumber, Buffer); + else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer); + } else printk("%s", Buffer); } BeginningOfLine = (Buffer[Length-1] == '\n'); @@ -4357,364 +4470,548 @@ /* - BusLogic_Setup handles processing of Kernel Command Line Arguments. + BusLogic_ParseKeyword parses an individual option keyword. It returns true + and updates the pointer if the keyword is recognized and false otherwise. +*/ - For the BusLogic driver, a Kernel Command Line Entry comprises the driver - identifier "BusLogic=" optionally followed by a comma-separated sequence of - integers and then optionally followed by a comma-separated sequence of - strings. Each command line entry applies to one BusLogic Host Adapter. - Multiple command line entries may be used in systems which contain multiple - BusLogic Host Adapters. +static boolean BusLogic_ParseKeyword(char **StringPointer, char *Keyword) +{ + char *Pointer = *StringPointer; + while (*Keyword != '\0') + { + char StringChar = *Pointer++; + char KeywordChar = *Keyword++; + if (StringChar >= 'A' && StringChar <= 'Z') + StringChar += 'a' - 'Z'; + if (KeywordChar >= 'A' && KeywordChar <= 'Z') + KeywordChar += 'a' - 'Z'; + if (StringChar != KeywordChar) return false; + } + *StringPointer = Pointer; + return true; +} - The first integer specified is the I/O Address at which the Host Adapter is - located. If unspecified, it defaults to 0 which means to apply this entry to - the first BusLogic Host Adapter found during the default probe sequence. If - any I/O Address parameters are provided on the command line, then the default - probe sequence is omitted. - - The second integer specified is the Tagged Queue Depth to use for Target - Devices that support Tagged Queuing. The Queue Depth is the number of SCSI - commands that are allowed to be concurrently presented for execution. If - unspecified, it defaults to 0 which means to use a value determined - automatically based on the Host Adapter's Total Queue Depth and the number, - type, speed, and capabilities of the detected Target Devices. For Host - Adapters that require ISA Bounce Buffers, the Tagged Queue Depth is - automatically set to BusLogic_TaggedQueueDepthBounceBuffers to avoid - excessive preallocation of DMA Bounce Buffer memory. Target Devices that do - not support Tagged Queuing use a Queue Depth of BusLogic_UntaggedQueueDepth. - - The third integer specified is the Bus Settle Time in seconds. This is - the amount of time to wait between a Host Adapter Hard Reset which initiates - a SCSI Bus Reset and issuing any SCSI Commands. If unspecified, it defaults - to 0 which means to use the value of BusLogic_DefaultBusSettleTime. - - The fourth integer specified is the Local Options. If unspecified, it - defaults to 0. Note that Local Options are only applied to a specific Host - Adapter. - The fifth integer specified is the Global Options. If unspecified, it - defaults to 0. Note that Global Options are applied across all Host - Adapters. +/* + BusLogic_ParseDriverOptions handles processing of BusLogic Driver Options + specifications. - The string options are used to provide control over Tagged Queuing, Error - Recovery, and Host Adapter Probing. + BusLogic Driver Options may be specified either via the Linux Kernel Command + Line or via the Loadable Kernel Module Installation Facility. Driver Options + for multiple host adapters may be specified either by separating the option + strings by a semicolon, or by specifying multiple "BusLogic=" strings on the + command line. Individual option specifications for a single host adapter are + separated by commas. The Probing and Debugging Options apply to all host + adapters whereas the remaining options apply individually only to the + selected host adapter. - The Tagged Queuing specification begins with "TQ:" and allows for explicitly - specifying whether Tagged Queuing is permitted on Target Devices that support - it. The following specification options are available: - - TQ:Default Tagged Queuing will be permitted based on the firmware - version of the BusLogic Host Adapter and based on - whether the Tagged Queue Depth value allows queuing - multiple commands. - - TQ:Enable Tagged Queuing will be enabled for all Target Devices - on this Host Adapter overriding any limitation that - would otherwise be imposed based on the Host Adapter - firmware version. - - TQ:Disable Tagged Queuing will be disabled for all Target Devices - on this Host Adapter. - - TQ: Tagged Queuing will be controlled individually for each - Target Device. is a sequence of "Y", - "N", and "X" characters. "Y" enabled Tagged Queuing, - "N" disables Tagged Queuing, and "X" accepts the - default based on the firmware version. The first - character refers to Target Device 0, the second to - Target Device 1, and so on; if the sequence of "Y", - "N", and "X" characters does not cover all the Target - Devices, unspecified characters are assumed to be "X". - - Note that explicitly requesting Tagged Queuing may lead to problems; this - facility is provided primarily to allow disabling Tagged Queuing on Target - Devices that do not implement it correctly. - - The Error Recovery Strategy specification begins with "ER:" and allows for - explicitly specifying the Error Recovery action to be performed when - ResetCommand is called due to a SCSI Command failing to complete - successfully. The following specification options are available: - - ER:Default Error Recovery will select between the Hard Reset and - Bus Device Reset options based on the recommendation - of the SCSI Subsystem. - - ER:HardReset Error Recovery will initiate a Host Adapter Hard Reset - which also causes a SCSI Bus Reset. - - ER:BusDeviceReset Error Recovery will send a Bus Device Reset message to - the individual Target Device causing the error. If - Error Recovery is again initiated for this Target - Device and no SCSI Command to this Target Device has - completed successfully since the Bus Device Reset - message was sent, then a Hard Reset will be attempted. - - ER:None Error Recovery will be suppressed. This option should - only be selected if a SCSI Bus Reset or Bus Device - Reset will cause the Target Device to fail completely - and unrecoverably. - - ER: Error Recovery will be controlled individually for each - Target Device. is a sequence of "D", - "H", "B", and "N" characters. "D" selects Default, "H" - selects Hard Reset, "B" selects Bus Device Reset, and - "N" selects None. The first character refers to Target - Device 0, the second to Target Device 1, and so on; if - the sequence of "D", "H", "B", and "N" characters does - not cover all the possible Target Devices, unspecified - characters are assumed to be "D". - - The Host Adapter Probing specification comprises the following strings: - - NoProbe No probing of any kind is to be performed, and hence - no BusLogic Host Adapters will be detected. - - NoProbeISA No probing of the standard ISA I/O Addresses will - be done, and hence only PCI MultiMaster and FlashPoint - Host Adapters will be detected. - - NoProbePCI No interrogation of PCI Configuration Space will be - made, and hence only ISA Multimaster Host Adapters - will be detected, as well as PCI Multimaster Host - Adapters that have their ISA Compatible I/O Port - set to "Primary" or "Alternate". - - NoSortPCI PCI MultiMaster Host Adapters will be enumerated in - the order provided by the PCI BIOS, ignoring any - setting of the AutoSCSI "Use Bus And Device # For PCI - Scanning Seq." option. - - MultiMasterFirst By default, if both FlashPoint and PCI MultiMaster - Host Adapters are present, this driver will probe for - FlashPoint Host Adapters first unless the BIOS primary - disk is controlled by the first PCI MultiMaster Host - Adapter, in which case MultiMaster Host Adapters will - be probed first. This option forces MultiMaster Host - Adapters to be probed first. - - FlashPointFirst By default, if both FlashPoint and PCI MultiMaster - Host Adapters are present, this driver will probe for - FlashPoint Host Adapters first unless the BIOS primary - disk is controlled by the first PCI MultiMaster Host - Adapter, in which case MultiMaster Host Adapters will - be probed first. This option forces FlashPoint Host - Adapters to be probed first. - - Debug Sets all the tracing bits in BusLogic_GlobalOptions. - -*/ - -void BusLogic_Setup(char *Strings, int *Integers) -{ - BusLogic_CommandLineEntry_T *CommandLineEntry = - &BusLogic_CommandLineEntries[BusLogic_CommandLineEntryCount++]; - int IntegerCount = Integers[0]; - int TargetID, i; - CommandLineEntry->IO_Address = 0; - CommandLineEntry->TaggedQueueDepth = 0; - CommandLineEntry->BusSettleTime = 0; - CommandLineEntry->TaggedQueuingPermitted = 0; - CommandLineEntry->TaggedQueuingPermittedMask = 0; - CommandLineEntry->LocalOptions.All = 0; - memset(CommandLineEntry->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_Default, - sizeof(CommandLineEntry->ErrorRecoveryStrategy)); - if (IntegerCount > 5) - BusLogic_Error("BusLogic: Unexpected Command Line Integers " - "ignored\n", NULL); - if (IntegerCount >= 1) - { - BusLogic_IO_Address_T IO_Address = Integers[1]; - if (IO_Address > 0) - { - BusLogic_ProbeInfo_T *ProbeInfo; - for (i = 0; ; i++) - if (BusLogic_ISA_StandardAddresses[i] == 0) - { - BusLogic_Error("BusLogic: Invalid Command Line Entry " - "(illegal I/O Address 0x%X)\n", - NULL, IO_Address); - return; - } - else if (i < BusLogic_ProbeInfoCount && - IO_Address == BusLogic_ProbeInfoList[i].IO_Address) - { - BusLogic_Error("BusLogic: Invalid Command Line Entry " - "(duplicate I/O Address 0x%X)\n", - NULL, IO_Address); - return; - } - else if (IO_Address >= 0x400 || - IO_Address == BusLogic_ISA_StandardAddresses[i]) break; - ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - } - CommandLineEntry->IO_Address = IO_Address; - } - if (IntegerCount >= 2) - { - unsigned short TaggedQueueDepth = Integers[2]; - if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth) - { - BusLogic_Error("BusLogic: Invalid Command Line Entry " - "(illegal Tagged Queue Depth %d)\n", - NULL, TaggedQueueDepth); + The BusLogic Driver Probing Options comprise the following: + + IO: + + The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI + MultiMaster Host Adapter. If neither "IO:" nor "NoProbeISA" options are + specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses + will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134). Multiple + "IO:" options may be specified to precisely determine the I/O Addresses to + be probed, but the probe order will always follow the standard list. + + NoProbe + + The "NoProbe" option disables all probing and therefore no BusLogic Host + Adapters will be detected. + + NoProbeISA + + The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O + Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters + will be detected. + + NoProbePCI + + The "NoProbePCI" options disables the interrogation of PCI Configuration + Space and therefore only ISA Multimaster Host Adapters will be detected, as + well as PCI Multimaster Host Adapters that have their ISA Compatible I/O + Port set to "Primary" or "Alternate". + + NoSortPCI + + The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be + enumerated in the order provided by the PCI BIOS, ignoring any setting of + the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option. + + MultiMasterFirst + + The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed + before FlashPoint Host Adapters. By default, if both FlashPoint and PCI + MultiMaster Host Adapters are present, this driver will probe for + FlashPoint Host Adapters first unless the BIOS primary disk is controlled + by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host + Adapters will be probed first. + + FlashPointFirst + + The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed + before MultiMaster Host Adapters. + + The BusLogic Driver Tagged Queuing Options allow for explicitly specifying + the Queue Depth and whether Tagged Queuing is permitted for each Target + Device (assuming that the Target Device supports Tagged Queuing). The Queue + Depth is the number of SCSI Commands that are allowed to be concurrently + presented for execution (either to the Host Adapter or Target Device). Note + that explicitly enabling Tagged Queuing may lead to problems; the option to + enable or disable Tagged Queuing is provided primarily to allow disabling + Tagged Queuing on Target Devices that do not implement it correctly. The + following options are available: + + QueueDepth: + + The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all + Target Devices that support Tagged Queuing. If no Queue Depth option is + provided, the Queue Depth will be determined automatically based on the + Host Adapter's Total Queue Depth and the number, type, speed, and + capabilities of the detected Target Devices. For Host Adapters that + require ISA Bounce Buffers, the Queue Depth is automatically set by default + to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA + Bounce Buffer memory. Target Devices that do not support Tagged Queuing + always use a Queue Depth of BusLogic_UntaggedQueueDepth. + + QueueDepth:[,...] + + The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth + individually for each Target Device. If an is omitted, the + associated Target Device will have its Queue Depth selected automatically. + + TaggedQueuing:Default + + The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing + based on the firmware version of the BusLogic Host Adapter and based on + whether the Queue Depth allows queuing multiple commands. + + TaggedQueuing:Enable + + The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for + all Target Devices on this Host Adapter, overriding any limitation that + would otherwise be imposed based on the Host Adapter firmware version. + + TaggedQueuing:Disable + + The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing + for all Target Devices on this Host Adapter. + + TaggedQueuing: + + The "TaggedQueuing:" or "TQ:" option controls + Tagged Queuing individually for each Target Device. is a + sequence of "Y", "N", and "X" characters. "Y" enables Tagged Queuing, "N" + disables Tagged Queuing, and "X" accepts the default based on the firmware + version. The first character refers to Target Device 0, the second to + Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters + does not cover all the Target Devices, unspecified characters are assumed + to be "X". + + The BusLogic Driver Error Recovery Option allows for explicitly specifying + the Error Recovery action to be performed when BusLogic_ResetCommand is + called due to a SCSI Command failing to complete successfully. The following + options are available: + + ErrorRecovery:Default + + The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard + Reset and Bus Device Reset options based on the recommendation of the SCSI + Subsystem. + + ErrorRecovery:HardReset + + The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host + Adapter Hard Reset which also causes a SCSI Bus Reset. + + ErrorRecovery:BusDeviceReset + + The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send + a Bus Device Reset message to the individual Target Device causing the + error. If Error Recovery is again initiated for this Target Device and no + SCSI Command to this Target Device has completed successfully since the Bus + Device Reset message was sent, then a Hard Reset will be attempted. + + ErrorRecovery:None + + The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery. + This option should only be selected if a SCSI Bus Reset or Bus Device Reset + will cause the Target Device or a critical operation to suffer a complete + and unrecoverable failure. + + ErrorRecovery: + + The "ErrorRecovery:" or "ER:" option controls + Error Recovery individually for each Target Device. is a + sequence of "D", "H", "B", and "N" characters. "D" selects Default, "H" + selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None. + The first character refers to Target Device 0, the second to Target Device + 1, and so on; if the sequence of "D", "H", "B", and "N" characters does not + cover all the possible Target Devices, unspecified characters are assumed + to be "D". + + The BusLogic Driver Miscellaneous Options comprise the following: + + BusSettleTime: + + The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in + seconds. The Bus Settle Time is the amount of time to wait between a Host + Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI + Commands. If unspecified, it defaults to BusLogic_DefaultBusSettleTime. + + InhibitTargetInquiry + + The "InhibitTargetInquiry" option inhibits the execution of an Inquire + Target Devices or Inquire Installed Devices command on MultiMaster Host + Adapters. This may be necessary with some older Target Devices that do not + respond correctly when Logical Units above 0 are addressed. + + The BusLogic Driver Debugging Options comprise the following: + + TraceProbe + + The "TraceProbe" option enables tracing of Host Adapter Probing. + + TraceHardwareReset + + The "TraceHardwareReset" option enables tracing of Host Adapter Hardware + Reset. + + TraceConfiguration + + The "TraceConfiguration" option enables tracing of Host Adapter + Configuration. + + TraceErrors + + The "TraceErrors" option enables tracing of SCSI Commands that return an + error from the Target Device. The CDB and Sense Data will be printed for + each SCSI Command that fails. + + Debug + + The "Debug" option enables all debugging options. + + The following examples demonstrate setting the Queue Depth for Target Devices + 1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target + Devices on the second host adapter to 31, and the Bus Settle Time on the + second host adapter to 30 seconds. + + Linux Kernel Command Line: + + linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30 + + LILO Linux Boot Loader (in /etc/lilo.conf): + + append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30" + + INSMOD Loadable Kernel Module Installation Facility: + + insmod BusLogic.o \ + 'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"' + + NOTE: Module Utilities 2.1.71 or later is required for correct parsing + of driver options containing commas. + +*/ + +static void BusLogic_ParseDriverOptions(char *OptionsString) +{ + while (true) + { + BusLogic_DriverOptions_T *DriverOptions = + &BusLogic_DriverOptions[BusLogic_DriverOptionsCount++]; + int TargetID; + memset(DriverOptions, 0, sizeof(BusLogic_DriverOptions_T)); + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_Default; + while (*OptionsString != '\0' && *OptionsString != ';') + { + /* Probing Options. */ + if (BusLogic_ParseKeyword(&OptionsString, "IO:")) + { + BusLogic_IO_Address_T IO_Address = + simple_strtoul(OptionsString, &OptionsString, 0); + BusLogic_ProbeOptions.LimitedProbeISA = true; + switch (IO_Address) + { + case 0x330: + BusLogic_ProbeOptions.Probe330 = true; + break; + case 0x334: + BusLogic_ProbeOptions.Probe334 = true; + break; + case 0x230: + BusLogic_ProbeOptions.Probe230 = true; + break; + case 0x234: + BusLogic_ProbeOptions.Probe234 = true; + break; + case 0x130: + BusLogic_ProbeOptions.Probe130 = true; + break; + case 0x134: + BusLogic_ProbeOptions.Probe134 = true; + break; + default: + BusLogic_Error("BusLogic: Invalid Driver Options " + "(illegal I/O Address 0x%X)\n", + NULL, IO_Address); + return; + } + } + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA")) + BusLogic_ProbeOptions.NoProbeISA = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI")) + BusLogic_ProbeOptions.NoProbePCI = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe")) + BusLogic_ProbeOptions.NoProbe = true; + else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI")) + BusLogic_ProbeOptions.NoSortPCI = true; + else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst")) + BusLogic_ProbeOptions.MultiMasterFirst = true; + else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst")) + BusLogic_ProbeOptions.FlashPointFirst = true; + /* Tagged Queuing Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") || + BusLogic_ParseKeyword(&OptionsString, "QD:[")) + { + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + { + unsigned short QueueDepth = + simple_strtoul(OptionsString, &OptionsString, 0); + if (QueueDepth > BusLogic_MaxTaggedQueueDepth) + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(illegal Queue Depth %d)\n", + NULL, QueueDepth); + return; + } + DriverOptions->QueueDepth[TargetID] = QueueDepth; + if (*OptionsString == ',') + OptionsString++; + else if (*OptionsString == ']') + break; + else + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(',' or ']' expected at '%s')\n", + NULL, OptionsString); + return; + } + } + if (*OptionsString != ']') + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(']' expected at '%s')\n", + NULL, OptionsString); + return; + } + else OptionsString++; + } + else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") || + BusLogic_ParseKeyword(&OptionsString, "QD:")) + { + unsigned short QueueDepth = + simple_strtoul(OptionsString, &OptionsString, 0); + if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth) + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(illegal Queue Depth %d)\n", + NULL, QueueDepth); + return; + } + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->QueueDepth[TargetID] = QueueDepth; + } + else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") || + BusLogic_ParseKeyword(&OptionsString, "TQ:")) + { + if (BusLogic_ParseKeyword(&OptionsString, "Default")) + { + DriverOptions->TaggedQueuingPermitted = 0x0000; + DriverOptions->TaggedQueuingPermittedMask = 0x0000; + } + else if (BusLogic_ParseKeyword(&OptionsString, "Enable")) + { + DriverOptions->TaggedQueuingPermitted = 0xFFFF; + DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; + } + else if (BusLogic_ParseKeyword(&OptionsString, "Disable")) + { + DriverOptions->TaggedQueuingPermitted = 0x0000; + DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; + } + else + { + unsigned short TargetBit; + for (TargetID = 0, TargetBit = 1; + TargetID < BusLogic_MaxTargetDevices; + TargetID++, TargetBit <<= 1) + switch (*OptionsString++) + { + case 'Y': + DriverOptions->TaggedQueuingPermitted |= TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + break; + case 'N': + DriverOptions->TaggedQueuingPermitted &= ~TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + break; + case 'X': + break; + default: + OptionsString--; + TargetID = BusLogic_MaxTargetDevices; + break; + } + } + } + /* Error Recovery Option. */ + else if (BusLogic_ParseKeyword(&OptionsString, "ErrorRecovery:") || + BusLogic_ParseKeyword(&OptionsString, "ER:")) + { + if (BusLogic_ParseKeyword(&OptionsString, "Default")) + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_Default; + else if (BusLogic_ParseKeyword(&OptionsString, "HardReset")) + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_HardReset; + else if (BusLogic_ParseKeyword(&OptionsString, "BusDeviceReset")) + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_BusDeviceReset; + else if (BusLogic_ParseKeyword(&OptionsString, "None")) + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_None; + else + for (TargetID = 0; + TargetID < BusLogic_MaxTargetDevices; + TargetID++) + switch (*OptionsString++) + { + case 'D': + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_Default; + break; + case 'H': + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_HardReset; + break; + case 'B': + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_BusDeviceReset; + break; + case 'N': + DriverOptions->ErrorRecoveryStrategy[TargetID] = + BusLogic_ErrorRecovery_None; + break; + default: + OptionsString--; + TargetID = BusLogic_MaxTargetDevices; + break; + } + } + /* Miscellaneous Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") || + BusLogic_ParseKeyword(&OptionsString, "BST:")) + { + unsigned short BusSettleTime = + simple_strtoul(OptionsString, &OptionsString, 0); + if (BusSettleTime > 5 * 60) + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(illegal Bus Settle Time %d)\n", + NULL, BusSettleTime); + return; + } + DriverOptions->BusSettleTime = BusSettleTime; + } + else if (BusLogic_ParseKeyword(&OptionsString, + "InhibitTargetInquiry")) + DriverOptions->LocalOptions.InhibitTargetInquiry = true; + /* Debugging Options. */ + else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe")) + BusLogic_GlobalOptions.TraceProbe = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset")) + BusLogic_GlobalOptions.TraceHardwareReset = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration")) + BusLogic_GlobalOptions.TraceConfiguration = true; + else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors")) + BusLogic_GlobalOptions.TraceErrors = true; + else if (BusLogic_ParseKeyword(&OptionsString, "Debug")) + { + BusLogic_GlobalOptions.TraceProbe = true; + BusLogic_GlobalOptions.TraceHardwareReset = true; + BusLogic_GlobalOptions.TraceConfiguration = true; + BusLogic_GlobalOptions.TraceErrors = true; + } + if (*OptionsString == ',') + OptionsString++; + else if (*OptionsString != ';' && *OptionsString != '\0') + { + BusLogic_Error("BusLogic: Unexpected Driver Option '%s' " + "ignored\n", NULL, OptionsString); + *OptionsString = '\0'; + } + } + if (!(BusLogic_DriverOptionsCount == 0 || + BusLogic_ProbeInfoCount == 0 || + BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount)) + { + BusLogic_Error("BusLogic: Invalid Driver Options " + "(all or no I/O Addresses must be specified)\n", NULL); return; } - CommandLineEntry->TaggedQueueDepth = TaggedQueueDepth; + /* + Tagged Queuing is disabled when the Queue Depth is 1 since queuing + multiple commands is not possible. + */ + for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) + if (DriverOptions->QueueDepth[TargetID] == 1) + { + unsigned short TargetBit = 1 << TargetID; + DriverOptions->TaggedQueuingPermitted &= ~TargetBit; + DriverOptions->TaggedQueuingPermittedMask |= TargetBit; + } + if (*OptionsString == ';') OptionsString++; + if (*OptionsString == '\0') return; } - if (IntegerCount >= 3) - CommandLineEntry->BusSettleTime = Integers[3]; - if (IntegerCount >= 4) - CommandLineEntry->LocalOptions.All = Integers[4]; - if (IntegerCount >= 5) - BusLogic_GlobalOptions.All |= Integers[5]; - if (!(BusLogic_CommandLineEntryCount == 0 || - BusLogic_ProbeInfoCount == 0 || - BusLogic_CommandLineEntryCount == BusLogic_ProbeInfoCount)) +} + + +/* + BusLogic_Setup handles processing of Kernel Command Line Arguments. +*/ + +void BusLogic_Setup(char *CommandLineString, int *CommandLineIntegers) +{ + if (CommandLineIntegers[0] != 0) { - BusLogic_Error("BusLogic: Invalid Command Line Entry " - "(all or no I/O Addresses must be specified)\n", NULL); + BusLogic_Error("BusLogic: Obsolete Command Line Entry " + "Format Ignored\n", NULL); return; } - if (Strings == NULL) return; - while (*Strings != '\0') - if (strncmp(Strings, "TQ:", 3) == 0) - { - Strings += 3; - if (strncmp(Strings, "Default", 7) == 0) - Strings += 7; - else if (strncmp(Strings, "Enable", 6) == 0) - { - Strings += 6; - CommandLineEntry->TaggedQueuingPermitted = 0xFFFF; - CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF; - } - else if (strncmp(Strings, "Disable", 7) == 0) - { - Strings += 7; - CommandLineEntry->TaggedQueuingPermitted = 0x0000; - CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF; - } - else - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - switch (*Strings++) - { - case 'Y': - CommandLineEntry->TaggedQueuingPermitted |= 1 << TargetID; - CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID; - break; - case 'N': - CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID; - break; - case 'X': - break; - default: - Strings--; - TargetID = BusLogic_MaxTargetDevices; - break; - } - } - else if (strncmp(Strings, "ER:", 3) == 0) - { - Strings += 3; - if (strncmp(Strings, "Default", 7) == 0) - Strings += 7; - else if (strncmp(Strings, "HardReset", 9) == 0) - { - Strings += 9; - memset(CommandLineEntry->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_HardReset, - sizeof(CommandLineEntry->ErrorRecoveryStrategy)); - } - else if (strncmp(Strings, "BusDeviceReset", 14) == 0) - { - Strings += 14; - memset(CommandLineEntry->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_BusDeviceReset, - sizeof(CommandLineEntry->ErrorRecoveryStrategy)); - } - else if (strncmp(Strings, "None", 4) == 0) - { - Strings += 4; - memset(CommandLineEntry->ErrorRecoveryStrategy, - BusLogic_ErrorRecovery_None, - sizeof(CommandLineEntry->ErrorRecoveryStrategy)); - } - else - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - switch (*Strings++) - { - case 'D': - CommandLineEntry->ErrorRecoveryStrategy[TargetID] = - BusLogic_ErrorRecovery_Default; - break; - case 'H': - CommandLineEntry->ErrorRecoveryStrategy[TargetID] = - BusLogic_ErrorRecovery_HardReset; - break; - case 'B': - CommandLineEntry->ErrorRecoveryStrategy[TargetID] = - BusLogic_ErrorRecovery_BusDeviceReset; - break; - case 'N': - CommandLineEntry->ErrorRecoveryStrategy[TargetID] = - BusLogic_ErrorRecovery_None; - break; - default: - Strings--; - TargetID = BusLogic_MaxTargetDevices; - break; - } - } - else if (strcmp(Strings, "NoProbe") == 0 || - strcmp(Strings, "noprobe") == 0) - { - Strings += 7; - BusLogic_ProbeOptions.Bits.NoProbe = true; - } - else if (strncmp(Strings, "NoProbeISA", 10) == 0) - { - Strings += 10; - BusLogic_ProbeOptions.Bits.NoProbeISA = true; - } - else if (strncmp(Strings, "NoProbePCI", 10) == 0) - { - Strings += 10; - BusLogic_ProbeOptions.Bits.NoProbePCI = true; - } - else if (strncmp(Strings, "NoSortPCI", 9) == 0) - { - Strings += 9; - BusLogic_ProbeOptions.Bits.NoSortPCI = true; - } - else if (strncmp(Strings, "MultiMasterFirst", 16) == 0) - { - Strings += 16; - BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst = true; - } - else if (strncmp(Strings, "FlashPointFirst", 15) == 0) - { - Strings += 15; - BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst = true; - } - else if (strncmp(Strings, "Debug", 5) == 0) - { - Strings += 5; - BusLogic_GlobalOptions.Bits.TraceProbe = true; - BusLogic_GlobalOptions.Bits.TraceHardReset = true; - BusLogic_GlobalOptions.Bits.TraceConfiguration = true; - BusLogic_GlobalOptions.Bits.TraceErrors = true; - } - else if (*Strings == ',') - Strings++; - else - { - BusLogic_Error("BusLogic: Unexpected Command Line String '%s' " - "ignored\n", NULL, Strings); - break; - } + if (CommandLineString == NULL || *CommandLineString == '\0') return; + BusLogic_ParseDriverOptions(CommandLineString); } @@ -4723,6 +5020,8 @@ */ #ifdef MODULE + +MODULE_PARM(BusLogic_Options, "s"); SCSI_Host_Template_T driver_template = BUSLOGIC; diff -ur --new-file old/linux/drivers/scsi/BusLogic.h new/linux/drivers/scsi/BusLogic.h --- old/linux/drivers/scsi/BusLogic.h Tue Jan 13 01:44:36 1998 +++ new/linux/drivers/scsi/BusLogic.h Wed Mar 18 06:43:47 1998 @@ -6,8 +6,7 @@ This program is free software; you may redistribute and/or modify it under the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation, provided that none of the source code or runtime - copyright notices are removed or modified. + Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY @@ -27,6 +26,9 @@ */ +#include + + /* Define types for some of the structures that interface with the rest of the Linux Kernel and SCSI Subsystem. @@ -35,6 +37,7 @@ typedef kdev_t KernelDevice_T; typedef struct proc_dir_entry PROC_DirectoryEntry_T; typedef struct pt_regs Registers_T; +typedef struct partition PartitionTable_T; typedef Scsi_Host_Template SCSI_Host_Template_T; typedef struct Scsi_Host SCSI_Host_T; typedef struct scsi_device SCSI_Device_T; @@ -63,19 +66,19 @@ Define the BusLogic SCSI Host Template structure. */ -#define BUSLOGIC \ - { proc_dir: &BusLogic_ProcDirectoryEntry, /* /proc Directory Entry */ \ - proc_info: BusLogic_ProcDirectoryInfo, /* /proc Info Function */ \ - name: "BusLogic", /* Driver Name */ \ - detect: BusLogic_DetectHostAdapter, /* Detect Host Adapter */ \ - release: BusLogic_ReleaseHostAdapter, /* Release Host Adapter */ \ - info: BusLogic_DriverInfo, /* Driver Info Function */ \ - queuecommand: BusLogic_QueueCommand, /* Queue Command Function */ \ - abort: BusLogic_AbortCommand, /* Abort Command Function */ \ - reset: BusLogic_ResetCommand, /* Reset Command Function */ \ - bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \ - unchecked_isa_dma: 1, /* Default Unchecked ISA DMA */ \ - use_clustering: ENABLE_CLUSTERING } /* Enable Clustering */ +#define BUSLOGIC \ + { proc_dir: &BusLogic_ProcDirectoryEntry, /* ProcFS Directory Entry */ \ + proc_info: BusLogic_ProcDirectoryInfo, /* ProcFS Info Function */ \ + name: "BusLogic", /* Driver Name */ \ + detect: BusLogic_DetectHostAdapter, /* Detect Host Adapter */ \ + release: BusLogic_ReleaseHostAdapter, /* Release Host Adapter */ \ + info: BusLogic_DriverInfo, /* Driver Info Function */ \ + queuecommand: BusLogic_QueueCommand, /* Queue Command Function */ \ + abort: BusLogic_AbortCommand, /* Abort Command Function */ \ + reset: BusLogic_ResetCommand, /* Reset Command Function */ \ + bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \ + unchecked_isa_dma: 1, /* Default Initial Value */ \ + use_clustering: ENABLE_CLUSTERING } /* Enable Clustering */ /* @@ -86,6 +89,24 @@ /* + FlashPoint support is only available for the Intel x86 Architecture with + CONFIG_PCI set. +*/ + +#ifndef __i386__ +#undef CONFIG_SCSI_OMIT_FLASHPOINT +#define CONFIG_SCSI_OMIT_FLASHPOINT +#endif + +#ifndef CONFIG_PCI +#undef CONFIG_SCSI_OMIT_FLASHPOINT +#define CONFIG_SCSI_OMIT_FLASHPOINT +#define BusLogic_InitializeProbeInfoListISA \ + BusLogic_InitializeProbeInfoList +#endif + + +/* Define the maximum number of BusLogic Host Adapters supported by this driver. */ @@ -109,16 +130,17 @@ /* - Define the maximum, preferred, and default Queue Depth to allow for Target - Devices depending on whether or not they support Tagged Queuing and whether - or not ISA Bounce Buffers are required. + Define the maximum, maximum automatic, minimum automatic, and default Queue + Depth to allow for Target Devices depending on whether or not they support + Tagged Queuing and whether or not ISA Bounce Buffers are required. */ -#define BusLogic_MaxTaggedQueueDepth 63 -#define BusLogic_PreferredTaggedQueueDepth 28 -#define BusLogic_TaggedQueueDepthBounceBuffers 2 -#define BusLogic_TaggedQueueDepthAutomatic 0 +#define BusLogic_MaxTaggedQueueDepth 64 +#define BusLogic_MaxAutomaticTaggedQueueDepth 28 +#define BusLogic_MinAutomaticTaggedQueueDepth 7 +#define BusLogic_TaggedQueueDepthBB 3 #define BusLogic_UntaggedQueueDepth 3 +#define BusLogic_UntaggedQueueDepthBB 2 /* @@ -132,11 +154,29 @@ /* + Define the maximum number of Mailboxes that should be used for MultiMaster + Host Adapters. This number is chosen to be larger than the maximum Host + Adapter Queue Depth and small enough so that the Host Adapter structure + does not cross an allocation block size boundary. +*/ + +#define BusLogic_MaxMailboxes 211 + + +/* + Define the number of CCBs that should be allocated as a group to optimize + Kernel memory allocation. +*/ + +#define BusLogic_CCB_AllocationGroupSize 7 + + +/* Define the Host Adapter Line and Message Buffer Sizes. */ #define BusLogic_LineBufferSize 100 -#define BusLogic_MessageBufferSize 9900 +#define BusLogic_MessageBufferSize 9700 /* @@ -155,7 +195,27 @@ static char *BusLogic_MessageLevelMap[] = - { KERN_INFO, KERN_INFO, KERN_NOTICE, KERN_WARNING, KERN_ERR }; + { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR }; + + +/* + Define Driver Message macros. +*/ + +#define BusLogic_Announce(Format, Arguments...) \ + BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments) + +#define BusLogic_Info(Format, Arguments...) \ + BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments) + +#define BusLogic_Notice(Format, Arguments...) \ + BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments) + +#define BusLogic_Warning(Format, Arguments...) \ + BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments) + +#define BusLogic_Error(Format, Arguments...) \ + BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments) /* @@ -175,11 +235,34 @@ #define BusLogic_FlashPointAddressCount 256 static int - BusLogic_HostAdapter_AddressCount[3] = + BusLogic_HostAdapterAddressCount[3] = { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount }; /* + Define macros for testing the Host Adapter Type. +*/ + +#ifndef CONFIG_SCSI_OMIT_FLASHPOINT + +#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ + (HostAdapter->HostAdapterType == BusLogic_MultiMaster) + +#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ + (HostAdapter->HostAdapterType == BusLogic_FlashPoint) + +#else + +#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ + (true) + +#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ + (false) + +#endif + + +/* Define the possible Host Adapter Bus Types. */ @@ -192,6 +275,7 @@ BusLogic_VESA_Bus = 4, BusLogic_MCA_Bus = 5 } +__attribute__ ((packed)) BusLogic_HostAdapterBusType_T; static char @@ -245,6 +329,13 @@ /* + Define a 32 bit Base Address data type. +*/ + +typedef unsigned int BusLogic_Base_Address_T; + + +/* Define a 32 bit Bus Address data type. */ @@ -276,11 +367,10 @@ typedef struct BusLogic_ProbeInfo { + BusLogic_HostAdapterType_T HostAdapterType; + BusLogic_HostAdapterBusType_T HostAdapterBusType; BusLogic_IO_Address_T IO_Address; BusLogic_PCI_Address_T PCI_Address; - BusLogic_HostAdapterType_T HostAdapterType:2; - BusLogic_HostAdapterBusType_T HostAdapterBusType:3; - unsigned char :3; unsigned char Bus; unsigned char Device; unsigned char IRQ_Channel; @@ -289,35 +379,24 @@ /* - BusLogic_ISA_StandardAddresses is the list of standard ISA I/O Addresses at - which BusLogic MultiMaster Host Adapters may potentially be found. The first - I/O Address 0x330 is known as the "Primary" I/O Address. A Host Adapter - configured to use the Primary I/O Address will always be the preferred boot - device. -*/ - -#define BusLogic_ISA_StandardAddressesCount 6 - -static BusLogic_IO_Address_T - BusLogic_ISA_StandardAddresses[BusLogic_ISA_StandardAddressesCount] = - { 0x330, 0x334, 0x230, 0x234, 0x130, 0x134 }; - - -/* Define the Probe Options. */ -typedef union BusLogic_ProbeOptions +typedef struct BusLogic_ProbeOptions { - unsigned short All; - struct { - boolean NoProbe:1; /* Bit 0 */ - boolean NoProbeISA:1; /* Bit 1 */ - boolean NoProbePCI:1; /* Bit 2 */ - boolean NoSortPCI:1; /* Bit 3 */ - boolean ProbeMultiMasterFirst:1; /* Bit 4 */ - boolean ProbeFlashPointFirst:1; /* Bit 5 */ - } Bits; + boolean NoProbe:1; /* Bit 0 */ + boolean NoProbeISA:1; /* Bit 1 */ + boolean NoProbePCI:1; /* Bit 2 */ + boolean NoSortPCI:1; /* Bit 3 */ + boolean MultiMasterFirst:1; /* Bit 4 */ + boolean FlashPointFirst:1; /* Bit 5 */ + boolean LimitedProbeISA:1; /* Bit 6 */ + boolean Probe330:1; /* Bit 7 */ + boolean Probe334:1; /* Bit 8 */ + boolean Probe230:1; /* Bit 9 */ + boolean Probe234:1; /* Bit 10 */ + boolean Probe130:1; /* Bit 11 */ + boolean Probe134:1; /* Bit 12 */ } BusLogic_ProbeOptions_T; @@ -326,15 +405,12 @@ Define the Global Options. */ -typedef union BusLogic_GlobalOptions +typedef struct BusLogic_GlobalOptions { - unsigned short All; - struct { - boolean TraceProbe:1; /* Bit 0 */ - boolean TraceHardReset:1; /* Bit 1 */ - boolean TraceConfiguration:1; /* Bit 2 */ - boolean TraceErrors:1; /* Bit 3 */ - } Bits; + boolean TraceProbe:1; /* Bit 0 */ + boolean TraceHardwareReset:1; /* Bit 1 */ + boolean TraceConfiguration:1; /* Bit 2 */ + boolean TraceErrors:1; /* Bit 3 */ } BusLogic_GlobalOptions_T; @@ -343,13 +419,9 @@ Define the Local Options. */ -typedef union BusLogic_LocalOptions +typedef struct BusLogic_LocalOptions { - unsigned short All; - struct { - boolean InhibitTargetInquiry:1; /* Bit 0 */ - boolean InhibitInterruptTest:1; /* Bit 1 */ - } Bits; + boolean InhibitTargetInquiry:1; /* Bit 0 */ } BusLogic_LocalOptions_T; @@ -607,10 +679,13 @@ unsigned char Signature; /* Byte 17 */ unsigned char CharacterD; /* Byte 18 */ unsigned char HostBusType; /* Byte 19 */ - unsigned char :8; /* Byte 20 */ - unsigned char :8; /* Byte 21 */ + unsigned char WideTransfersPermittedID0to7; /* Byte 20 */ + unsigned char WideTransfersActiveID0to7; /* Byte 21 */ BusLogic_SynchronousValues8_T SynchronousValuesID8to15; /* Bytes 22-29 */ unsigned char DisconnectPermittedID8to15; /* Byte 30 */ + unsigned char :8; /* Byte 31 */ + unsigned char WideTransfersPermittedID8to15; /* Byte 32 */ + unsigned char WideTransfersActiveID8to15; /* Byte 33 */ } BusLogic_SetupInformation_T; @@ -1052,6 +1127,21 @@ /* + Define the Driver CCB Status Codes. +*/ + +typedef enum +{ + BusLogic_CCB_Free = 0, + BusLogic_CCB_Active = 1, + BusLogic_CCB_Completed = 2, + BusLogic_CCB_Reset = 3 +} +__attribute__ ((packed)) +BusLogic_CCB_Status_T; + + +/* Define the 32 Bit Mode Command Control Block (CCB) structure. The first 40 bytes are defined by and common to both the MultiMaster Firmware and the FlashPoint SCCB Manager. The next 60 bytes are defined by the FlashPoint @@ -1101,27 +1191,26 @@ FlashPoint SCCB Manager Defined Portion. */ void (*CallbackFunction)(struct BusLogic_CCB *); /* Bytes 40-43 */ - BusLogic_IO_Address_T BaseAddress; /* Bytes 44-47 */ + BusLogic_Base_Address_T BaseAddress; /* Bytes 44-47 */ BusLogic_CompletionCode_T CompletionCode; /* Byte 48 */ +#ifndef CONFIG_SCSI_OMIT_FLASHPOINT unsigned char :8; /* Byte 49 */ unsigned short OS_Flags; /* Bytes 50-51 */ unsigned char Private[48]; /* Bytes 52-99 */ +#endif /* BusLogic Linux Driver Defined Portion. */ - struct BusLogic_HostAdapter *HostAdapter; - SCSI_Command_T *Command; - enum { BusLogic_CCB_Free = 0, - BusLogic_CCB_Active = 1, - BusLogic_CCB_Completed = 2, - BusLogic_CCB_Reset = 3 } Status; + boolean AllocationGroupHead; + BusLogic_CCB_Status_T Status; unsigned long SerialNumber; + SCSI_Command_T *Command; + struct BusLogic_HostAdapter *HostAdapter; struct BusLogic_CCB *Next; struct BusLogic_CCB *NextAll; BusLogic_ScatterGatherSegment_T ScatterGatherList[BusLogic_ScatterGatherLimit]; } -__attribute__ ((packed)) BusLogic_CCB_T; @@ -1154,32 +1243,48 @@ /* - Define the Linux BusLogic Driver Command Line Entry structure. + Define the BusLogic Driver Options structure. */ -typedef struct BusLogic_CommandLineEntry +typedef struct BusLogic_DriverOptions { - BusLogic_IO_Address_T IO_Address; - unsigned short TaggedQueueDepth; - unsigned short BusSettleTime; unsigned short TaggedQueuingPermitted; unsigned short TaggedQueuingPermittedMask; + unsigned short BusSettleTime; BusLogic_LocalOptions_T LocalOptions; + unsigned char QueueDepth[BusLogic_MaxTargetDevices]; BusLogic_ErrorRecoveryStrategy_T ErrorRecoveryStrategy[BusLogic_MaxTargetDevices]; } -BusLogic_CommandLineEntry_T; +BusLogic_DriverOptions_T; /* - Define the Host Adapter Target Device Statistics structure. + Define the Host Adapter Target Flags structure. +*/ + +typedef struct BusLogic_TargetFlags +{ + boolean TargetExists:1; + boolean TaggedQueuingSupported:1; + boolean WideTransfersSupported:1; + boolean TaggedQueuingActive:1; + boolean WideTransfersActive:1; + boolean CommandSuccessfulFlag:1; + boolean TargetInfoReported:1; +} +BusLogic_TargetFlags_T; + + +/* + Define the Host Adapter Target Statistics structure. */ #define BusLogic_SizeBuckets 10 typedef unsigned int BusLogic_CommandSizeBuckets_T[BusLogic_SizeBuckets]; -typedef struct BusLogic_TargetDeviceStatistics +typedef struct BusLogic_TargetStatistics { unsigned int CommandsAttempted; unsigned int CommandsCompleted; @@ -1199,7 +1304,7 @@ unsigned short HostAdapterResetsAttempted; unsigned short HostAdapterResetsCompleted; } -BusLogic_TargetDeviceStatistics_T; +BusLogic_TargetStatistics_T; /* @@ -1218,7 +1323,7 @@ typedef struct FlashPoint_Info { - BusLogic_IO_Address_T BaseAddress; /* Bytes 0-3 */ + BusLogic_Base_Address_T BaseAddress; /* Bytes 0-3 */ boolean Present; /* Byte 4 */ unsigned char IRQ_Channel; /* Byte 5 */ unsigned char SCSI_ID; /* Byte 6 */ @@ -1253,12 +1358,14 @@ /* - Define the Linux BusLogic Driver Host Adapter structure. + Define the BusLogic Driver Host Adapter structure. */ typedef struct BusLogic_HostAdapter { SCSI_Host_T *SCSI_Host; + BusLogic_HostAdapterType_T HostAdapterType; + BusLogic_HostAdapterBusType_T HostAdapterBusType; BusLogic_IO_Address_T IO_Address; BusLogic_PCI_Address_T PCI_Address; unsigned short AddressCount; @@ -1267,18 +1374,16 @@ unsigned char FirmwareVersion[6]; unsigned char FullModelName[18]; unsigned char InterruptLabel[68]; + unsigned char Bus; + unsigned char Device; unsigned char IRQ_Channel; unsigned char DMA_Channel; unsigned char SCSI_ID; - unsigned char Bus; - unsigned char Device; - BusLogic_HostAdapterType_T HostAdapterType; - BusLogic_HostAdapterBusType_T HostAdapterBusType:3; boolean IRQ_ChannelAcquired:1; boolean DMA_ChannelAcquired:1; boolean ExtendedTranslationEnabled:1; boolean ParityCheckingEnabled:1; - boolean BusResetEnabled; + boolean BusResetEnabled:1; boolean LevelSensitiveInterrupt:1; boolean HostWideSCSI:1; boolean HostDifferentialSCSI:1; @@ -1292,8 +1397,9 @@ boolean StrictRoundRobinModeSupport:1; boolean SCAM_Enabled:1; boolean SCAM_Level2:1; - boolean HostAdapterInitialized; - boolean HostAdapterResetRequested:1; + boolean HostAdapterInitialized:1; + boolean HostAdapterExternalReset:1; + boolean HostAdapterInternalError:1; volatile boolean HostAdapterCommandCompleted:1; unsigned short HostAdapterScatterGatherLimit; unsigned short DriverScatterGatherLimit; @@ -1305,7 +1411,6 @@ unsigned short AllocatedCCBs; unsigned short DriverQueueDepth; unsigned short HostAdapterQueueDepth; - unsigned short TaggedQueueDepth; unsigned short UntaggedQueueDepth; unsigned short BusSettleTime; unsigned short SynchronousPermitted; @@ -1315,26 +1420,24 @@ unsigned short DisconnectPermitted; unsigned short TaggedQueuingPermitted; unsigned short ExternalHostAdapterResets; - BusLogic_LocalOptions_T LocalOptions; + unsigned short HostAdapterInternalErrors; + unsigned short TargetDeviceCount; + unsigned short MessageBufferLength; BusLogic_BusAddress_T BIOS_Address; - BusLogic_InstalledDevices_T InstalledDevices; - BusLogic_SynchronousValues_T SynchronousValues; - BusLogic_SynchronousPeriod_T SynchronousPeriod; - BusLogic_CommandLineEntry_T *CommandLineEntry; - FlashPoint_Info_T *FlashPointInfo; + BusLogic_DriverOptions_T *DriverOptions; + FlashPoint_Info_T FlashPointInfo; FlashPoint_CardHandle_T CardHandle; struct BusLogic_HostAdapter *Next; - char *MessageBuffer; - int MessageBufferLength; + struct BusLogic_HostAdapter *NextAll; BusLogic_CCB_T *All_CCBs; BusLogic_CCB_T *Free_CCBs; BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices]; BusLogic_ErrorRecoveryStrategy_T ErrorRecoveryStrategy[BusLogic_MaxTargetDevices]; - boolean TaggedQueuingSupported[BusLogic_MaxTargetDevices]; - boolean TaggedQueuingActive[BusLogic_MaxTargetDevices]; - boolean CommandSuccessfulFlag[BusLogic_MaxTargetDevices]; + BusLogic_TargetFlags_T TargetFlags[BusLogic_MaxTargetDevices]; unsigned char QueueDepth[BusLogic_MaxTargetDevices]; + unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices]; + unsigned char SynchronousOffset[BusLogic_MaxTargetDevices]; unsigned char ActiveCommands[BusLogic_MaxTargetDevices]; unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices]; unsigned long LastSequencePoint[BusLogic_MaxTargetDevices]; @@ -1346,7 +1449,11 @@ BusLogic_IncomingMailbox_T *FirstIncomingMailbox; BusLogic_IncomingMailbox_T *LastIncomingMailbox; BusLogic_IncomingMailbox_T *NextIncomingMailbox; - BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics; + BusLogic_TargetStatistics_T TargetStatistics[BusLogic_MaxTargetDevices]; + unsigned char MailboxSpace[BusLogic_MaxMailboxes + * (sizeof(BusLogic_OutgoingMailbox_T) + + sizeof(BusLogic_IncomingMailbox_T))]; + char MessageBuffer[BusLogic_MessageBufferSize]; } BusLogic_HostAdapter_T; @@ -1365,6 +1472,41 @@ /* + Define a structure for the SCSI Inquiry command results. +*/ + +typedef struct SCSI_Inquiry +{ + unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ + unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ + unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ + boolean RMB:1; /* Byte 1 Bit 7 */ + unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ + unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ + unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ + unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ + unsigned char :2; /* Byte 3 Bits 4-5 */ + boolean TrmIOP:1; /* Byte 3 Bit 6 */ + boolean AENC:1; /* Byte 3 Bit 7 */ + unsigned char AdditionalLength; /* Byte 4 */ + unsigned char :8; /* Byte 5 */ + unsigned char :8; /* Byte 6 */ + boolean SftRe:1; /* Byte 7 Bit 0 */ + boolean CmdQue:1; /* Byte 7 Bit 1 */ + boolean :1; /* Byte 7 Bit 2 */ + boolean Linked:1; /* Byte 7 Bit 3 */ + boolean Sync:1; /* Byte 7 Bit 4 */ + boolean WBus16:1; /* Byte 7 Bit 5 */ + boolean WBus32:1; /* Byte 7 Bit 6 */ + boolean RelAdr:1; /* Byte 7 Bit 7 */ + unsigned char VendorIdentification[8]; /* Bytes 8-15 */ + unsigned char ProductIdentification[16]; /* Bytes 16-31 */ + unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ +} +SCSI_Inquiry_T; + + +/* BusLogic_AcquireHostAdapterLock acquires exclusive access to Host Adapter. */ @@ -1540,6 +1682,19 @@ /* + Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and + 32 Bit Kernel Virtual Addresses. This avoids compilation warnings + on 64 Bit architectures. +*/ + +static inline +BusLogic_BusAddress_T Virtual_to_32Bit_Virtual(void *VirtualAddress) +{ + return (BusLogic_BusAddress_T) (unsigned long) VirtualAddress; +} + + +/* BusLogic_IncrementErrorCounter increments Error Counter by 1, stopping at 65535 rather than wrapping around to 0. */ @@ -1577,93 +1732,38 @@ { int Index = 0; if (Amount < 8*1024) - if (Amount < 2*1024) - Index = (Amount < 1*1024 ? 0 : 1); - else Index = (Amount < 4*1024 ? 2 : 3); + { + if (Amount < 2*1024) + Index = (Amount < 1*1024 ? 0 : 1); + else Index = (Amount < 4*1024 ? 2 : 3); + } else if (Amount < 128*1024) - if (Amount < 32*1024) - Index = (Amount < 16*1024 ? 4 : 5); - else Index = (Amount < 64*1024 ? 6 : 7); + { + if (Amount < 32*1024) + Index = (Amount < 16*1024 ? 4 : 5); + else Index = (Amount < 64*1024 ? 6 : 7); + } else Index = (Amount < 256*1024 ? 8 : 9); CommandSizeBuckets[Index]++; } /* - If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT, and use the - ISA only probe function as the general one. + Define compatibility macros between Linux 2.0 and Linux 2.1. */ -#ifndef CONFIG_PCI - -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT +#if LINUX_VERSION_CODE < 0x20100 -#define BusLogic_InitializeProbeInfoListISA BusLogic_InitializeProbeInfoList +#define MODULE_PARM(Variable, Type) #endif /* - FlashPoint support is only available for the Intel x86 Architecture. -*/ - -#ifndef __i386__ - -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT - -#endif - - -/* - Define macros for testing the Host Adapter Type. -*/ - -#ifndef CONFIG_SCSI_OMIT_FLASHPOINT - -#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ - (HostAdapter->HostAdapterType == BusLogic_MultiMaster) - -#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ - (HostAdapter->HostAdapterType == BusLogic_FlashPoint) - -#else - -#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ - (true) - -#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ - (false) - -#endif - - -/* - Define Driver Message Macros. -*/ - -#define BusLogic_Announce(Format, Arguments...) \ - BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments) - -#define BusLogic_Info(Format, Arguments...) \ - BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments) - -#define BusLogic_Notice(Format, Arguments...) \ - BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments) - -#define BusLogic_Warning(Format, Arguments...) \ - BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments) - -#define BusLogic_Error(Format, Arguments...) \ - BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments) - - -/* Define the version number of the FlashPoint Firmware (SCCB Manager). */ -#define FlashPoint_FirmwareVersion "5.01" +#define FlashPoint_FirmwareVersion "5.02" /* @@ -1671,35 +1771,22 @@ */ #define FlashPoint_NormalInterrupt 0x00 +#define FlashPoint_InternalError 0xFE #define FlashPoint_ExternalBusReset 0xFF /* - Define prototypes for the FlashPoint SCCB Manager Functions. -*/ - -extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *); -extern FlashPoint_CardHandle_T - FlashPoint_HardResetHostAdapter(FlashPoint_Info_T *); -extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *); -extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *); -extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T); -extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T); -extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T); - - -/* Define prototypes for the forward referenced BusLogic Driver Internal Functions. */ -static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *CCB); +static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *); static void BusLogic_InterruptHandler(int, void *, Registers_T *); static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *, - SCSI_Command_T *, - unsigned int); -static void BusLogic_Message(BusLogic_MessageLevel_T, char *Format, + SCSI_Command_T *, unsigned int); +static void BusLogic_Message(BusLogic_MessageLevel_T, char *, BusLogic_HostAdapter_T *, ...); +static void BusLogic_ParseDriverOptions(char *); #endif /* BusLogic_DriverVersion */ diff -ur --new-file old/linux/drivers/scsi/Config.in new/linux/drivers/scsi/Config.in --- old/linux/drivers/scsi/Config.in Mon Dec 22 02:04:48 1997 +++ new/linux/drivers/scsi/Config.in Fri Feb 27 04:35:33 1998 @@ -4,7 +4,7 @@ dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then - bool ' Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR + bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR fi dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI @@ -25,7 +25,7 @@ dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y - dep_tristate ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N + bool ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8 fi @@ -84,10 +84,11 @@ fi fi if [ "$CONFIG_MCA" = "y" ]; then - dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI - if [ "$CONFIG_SCSI_IBMMCA" != "n" ]; then - bool ' reset SCSI-devices while booting' CONFIG_SCSI_IBMMCA_DEV_RESET - fi + dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI + if [ "$CONFIG_SCSI_IBMMCA" != "n" ]; then + bool ' Standard SCSI-order' CONFIG_IBMMCA_SCSI_ORDER_STANDARD + bool ' Reset SCSI-devices at boottime' CONFIG_IBMMCA_SCSI_DEV_RESET + fi fi if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT @@ -122,7 +123,7 @@ # The actual configuration in any kernel release could change at any time as I hack it to # simulate various conditions that I am testing. # -if [ "`whoami`" = "eric" ]; then +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI fi if [ "$CONFIG_PPC" = "y" ]; then diff -ur --new-file old/linux/drivers/scsi/FlashPoint.c new/linux/drivers/scsi/FlashPoint.c --- old/linux/drivers/scsi/FlashPoint.c Mon Aug 11 09:10:00 1997 +++ new/linux/drivers/scsi/FlashPoint.c Sat Jan 31 11:00:00 1998 @@ -19,40 +19,15 @@ #include -/* - If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT. -*/ - -#ifndef CONFIG_PCI - -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT - -#endif - - -/* - FlashPoint support is only available for the Intel x86 Architecture. -*/ - -#ifndef __i386__ - -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT - -#endif - - #ifndef CONFIG_SCSI_OMIT_FLASHPOINT #define UNIX #define FW_TYPE _SCCB_MGR_ #define MAX_CARDS 8 +#undef BUSTYPE_PCI -#include - #define OS_InPortByte(port) inb(port) #define OS_InPortWord(port) inw(port) #define OS_InPortLong(port) inl(port) @@ -68,7 +43,7 @@ */ #define SccbMgr_sense_adapter FlashPoint_ProbeHostAdapter -#define SccbMgr_config_adapter FlashPoint_HardResetHostAdapter +#define SccbMgr_config_adapter FlashPoint_HardwareResetHostAdapter #define SccbMgr_unload_card FlashPoint_ReleaseHostAdapter #define SccbMgr_start_sccb FlashPoint_StartCCB #define SccbMgr_abort_sccb FlashPoint_AbortCCB @@ -169,6 +144,7 @@ #define stwidn FPT_stwidn #define sxfrp FPT_sxfrp #define utilEERead FPT_utilEERead +#define utilEEReadOrg FPT_utilEEReadOrg #define utilEESendCmdAddr FPT_utilEESendCmdAddr #define utilEEWrite FPT_utilEEWrite #define utilEEWriteOnOff FPT_utilEEWriteOnOff @@ -1317,9 +1293,9 @@ * * Description: Register definitions for HARPOON ASIC. * - * $Date: 1997/01/31 02:14:28 $ + * $Date: 1997/07/09 21:44:36 $ * - * $Revision: 1.6 $ + * $Revision: 1.9 $ * *----------------------------------------------------------------------*/ @@ -2070,9 +2046,14 @@ UCHAR RdStack(USHORT port, UCHAR index); void WrStack(USHORT portBase, UCHAR index, UCHAR data); UCHAR ChkIfChipInitialized(USHORT ioPort); + +#if defined(V302) UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun); +#endif + void SendMsg(USHORT port, UCHAR message); void queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code); +UCHAR scsellDOS(USHORT p_port, UCHAR targ_id); #else UCHAR sfm(ULONG port, PSCCB pcurrSCCB); void scsiStartAuto(ULONG port); @@ -2090,7 +2071,11 @@ UCHAR RdStack(ULONG port, UCHAR index); void WrStack(ULONG portBase, UCHAR index, UCHAR data); UCHAR ChkIfChipInitialized(ULONG ioPort); + +#if defined(V302) UCHAR GetTarLun(ULONG port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tar, PUCHAR lun); +#endif + void SendMsg(ULONG port, UCHAR message); void queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code); #endif @@ -2130,6 +2115,7 @@ void utilEEWriteOnOff(USHORT p_port,UCHAR p_mode); void utilEEWrite(USHORT p_port, USHORT ee_data, USHORT ee_addr); USHORT utilEERead(USHORT p_port, USHORT ee_addr); +USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr); void utilEESendCmdAddr(USHORT p_port, UCHAR ee_cmd, USHORT ee_addr); #else void Wait1Second(ULONG p_port); @@ -2137,6 +2123,7 @@ void utilEEWriteOnOff(ULONG p_port,UCHAR p_mode); void utilEEWrite(ULONG p_port, USHORT ee_data, USHORT ee_addr); USHORT utilEERead(ULONG p_port, USHORT ee_addr); +USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr); void utilEESendCmdAddr(ULONG p_port, UCHAR ee_cmd, USHORT ee_addr); #endif @@ -2339,7 +2326,7 @@ extern unsigned int SccbGlobalFlags; -#ident "$Id: sccb.c 1.17 1997/02/11 21:06:41 mohan Exp $" +#ident "$Id: sccb.c 1.18 1997/06/10 16:47:04 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -2353,9 +2340,9 @@ * Description: Functions relating to handling of the SCCB interface * between the device driver and the HARPOON. * - * $Date: 1997/02/11 21:06:41 $ + * $Date: 1997/06/10 16:47:04 $ * - * $Revision: 1.17 $ + * $Revision: 1.18 $ * *----------------------------------------------------------------------*/ @@ -2477,6 +2464,7 @@ if(ChkIfChipInitialized(ioport) == FALSE) { pCurrNvRam = NULL; + WR_HARPOON(ioport+hp_semaphore, 0x00); XbowInit(ioport, 0); /*Must Init the SCSI before attempting */ DiagEEPROM(ioport); } @@ -3036,6 +3024,7 @@ if(ChkIfChipInitialized(ioport) == FALSE) { pCurrNvRam = NULL; + WR_HARPOON(ioport+hp_semaphore, 0x00); XbowInit(ioport, 0); /*Must Init the SCSI before attempting */ DiagEEPROM(ioport); } @@ -4802,7 +4791,23 @@ may not show up if another device reselects us in 1.5us or less. SRR Wednesday, 3/8/1995. */ - while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL))) ; + while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)) && + !((RDW_HARPOON((ioport+hp_intstat)) & PHASE) && + RD_HARPOON((ioport+hp_scsisig)) == + (SCSI_BSY | SCSI_REQ | SCSI_CD | SCSI_MSG | SCSI_IOBIT))) ; + + /* + The additional loop exit condition above detects a timing problem + with the revision D/E harpoon chips. The caller should reset the + host adapter to recover when 0xFE is returned. + */ + if (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL))) + { + mOS_Lock((PSCCBcard)pCurrCard); + MENABLE_INT(ioport); + mOS_UnLock((PSCCBcard)pCurrCard); + return 0xFE; + } WRW_HARPOON((ioport+hp_intstat), (BUS_FREE | ITAR_DISC)); @@ -5347,7 +5352,7 @@ } #endif -#ident "$Id: sccb_dat.c 1.9 1997/01/31 02:12:58 mohan Exp $" +#ident "$Id: sccb_dat.c 1.10 1997/02/22 03:16:02 awin Exp $" /*---------------------------------------------------------------------- * * @@ -5361,9 +5366,9 @@ * Description: Functions relating to handling of the SCCB interface * between the device driver and the HARPOON. * - * $Date: 1997/01/31 02:12:58 $ + * $Date: 1997/02/22 03:16:02 $ * - * $Revision: 1.9 $ + * $Revision: 1.10 $ * *----------------------------------------------------------------------*/ @@ -5378,18 +5383,19 @@ /*#include */ /*#include */ +/* +** IMPORTANT NOTE!!! +** +** You MUST preassign all data to a valid value or zero. This is +** required due to the MS compiler bug under OS/2 and Solaris Real-Mode +** driver environment. +*/ + -#if defined(OS2) || defined (SOLARIS_REAL_MODE) -SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { 0 }; -SCCBCARD BL_Card[MAX_CARDS] = { 0 }; -SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { 0 }; -NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { 0 }; -#else -SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR]; -SCCBCARD BL_Card[MAX_CARDS]; -SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR]; -NVRAMINFO nvRamInfo[MAX_MB_CARDS]; -#endif +SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { { { 0 } } }; +SCCBCARD BL_Card[MAX_CARDS] = { { 0 } }; +SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { { { 0 } } }; +NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { { 0 } }; #if defined(OS2) @@ -5402,23 +5408,23 @@ #endif #if defined(DOS) -UCHAR first_time; +UCHAR first_time = 0; #endif -UCHAR mbCards; +UCHAR mbCards = 0; UCHAR scamHAString[] = {0x63, 0x07, 'B', 'U', 'S', 'L', 'O', 'G', 'I', 'C', \ ' ', 'B', 'T', '-', '9', '3', '0', \ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, \ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}; -USHORT default_intena; +USHORT default_intena = 0; #if defined(BUGBUG) -UCHAR debug_int[MAX_CARDS][debug_size]; -UCHAR debug_index[MAX_CARDS]; -UCHAR reserved_1[3]; +UCHAR debug_int[MAX_CARDS][debug_size] = { 0 }; +UCHAR debug_index[MAX_CARDS] = { 0 }; +UCHAR reserved_1[3] = { 0 }; #endif -#ident "$Id: scsi.c 1.19 1997/01/31 02:08:14 mohan Exp $" +#ident "$Id: scsi.c 1.23 1997/07/09 21:42:54 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -5433,9 +5439,9 @@ * selection/reselection, sync negotiation, message-in * decoding. * - * $Date: 1997/01/31 02:08:14 $ + * $Date: 1997/07/09 21:42:54 $ * - * $Revision: 1.19 $ + * $Revision: 1.23 $ * *----------------------------------------------------------------------*/ @@ -5483,11 +5489,13 @@ while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) && (TimeOutLoop++ < 20000) ){} + WR_HARPOON(port+hp_portctrl_0, SCSI_PORT); message = RD_HARPOON(port+hp_scsidata_0); - WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH)); + WR_HARPOON(port+hp_scsisig, SCSI_ACK + S_MSGI_PH); + if (TimeOutLoop > 20000) message = 0x00; /* force message byte = 0 if Time Out on Req */ @@ -5495,6 +5503,10 @@ if ((RDW_HARPOON((port+hp_intstat)) & PARITY) && (RD_HARPOON(port+hp_addstat) & SCSI_PAR_ERR)) { + WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH)); + WR_HARPOON(port+hp_xferstat, 0); + WR_HARPOON(port+hp_fiforead, 0); + WR_HARPOON(port+hp_fifowrite, 0); if (pCurrSCCB != NULL) { pCurrSCCB->Sccb_scsimsg = SMPARITY; @@ -5503,6 +5515,7 @@ do { ACCEPT_MSG_ATN(port); + TimeOutLoop = 0; while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) && (TimeOutLoop++ < 20000) ){} if (TimeOutLoop > 20000) @@ -5524,6 +5537,10 @@ }while(1); } + WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH)); + WR_HARPOON(port+hp_xferstat, 0); + WR_HARPOON(port+hp_fiforead, 0); + WR_HARPOON(port+hp_fifowrite, 0); return(message); } @@ -5894,12 +5911,20 @@ void sres(ULONG port, UCHAR p_card, PSCCBcard pCurrCard) #endif { + +#if defined(V302) #ifdef DOS UCHAR our_target,message, msgRetryCount; extern UCHAR lun, tag; #else UCHAR our_target,message,lun,tag, msgRetryCount; #endif + +#else /* V302 */ + UCHAR our_target, message, lun = 0, tag, msgRetryCount; +#endif /* V302 */ + + PSCCBMgr_tar_info currTar_Info; PSCCB currSCCB; @@ -5972,7 +5997,103 @@ msgRetryCount = 0; do { + +#if defined(V302) + message = GetTarLun(port, p_card, our_target, pCurrCard, &tag, &lun); + +#else /* V302 */ + + currTar_Info = &sccbMgrTbl[p_card][our_target]; + tag = 0; + + + while(!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) + { + if (! (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) + { + + WRW_HARPOON((port+hp_intstat), PHASE); + return; + } + } + + WRW_HARPOON((port+hp_intstat), PHASE); + if ((RD_HARPOON(port+hp_scsisig) & S_SCSI_PHZ) == S_MSGI_PH) + { + + message = sfm(port,pCurrCard->currentSCCB); + if (message) + { + + if (message <= (0x80 | LUN_MASK)) + { + lun = message & (UCHAR)LUN_MASK; + +#if !defined(DOS) + if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_TRYING) + { + if (currTar_Info->TarTagQ_Cnt != 0) + { + + if (!(currTar_Info->TarLUN_CA)) + { + ACCEPT_MSG(port); /*Release the ACK for ID msg. */ + + + message = sfm(port,pCurrCard->currentSCCB); + if (message) + { + ACCEPT_MSG(port); + } + + else + message = FALSE; + + if(message != FALSE) + { + tag = sfm(port,pCurrCard->currentSCCB); + + if (!(tag)) + message = FALSE; + } + + } /*C.A. exists! */ + + } /*End Q cnt != 0 */ + + } /*End Tag cmds supported! */ +#endif /* !DOS */ + + } /*End valid ID message. */ + + else + { + + ACCEPT_MSG_ATN(port); + } + + } /* End good id message. */ + + else + { + + message = FALSE; + } + } + else + { + ACCEPT_MSG_ATN(port); + + while (!(RDW_HARPOON((port+hp_intstat)) & (PHASE | RESET)) && + !(RD_HARPOON(port+hp_scsisig) & SCSI_REQ) && + (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ; + + return; + } + +#endif /* V302 */ + if(message == FALSE) { msgRetryCount++; @@ -6071,6 +6192,8 @@ (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ; } +#if defined(V302) + #if defined(DOS) UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun) #else @@ -6162,6 +6285,7 @@ return(TRUE); } +#endif /* V302 */ #if defined(DOS) void SendMsg(USHORT port, UCHAR message) @@ -6469,6 +6593,10 @@ ACCEPT_MSG(port); WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START)); } + }else + { + if(pCurrSCCB->Sccb_scsimsg == SMPARITY) + WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START)); } } @@ -7386,6 +7514,7 @@ p_sccb->Sccb_scsistat = BUS_FREE_ST; p_sccb->SccbStatus = SCCB_IN_PROCESS; p_sccb->Sccb_scsimsg = SMNO_OP; + } @@ -9222,7 +9351,7 @@ currSCCB->Sccb_XferCnt = currSCCB->DataLength - currSCCB->Sccb_ATC; } } -#ident "$Id: scam.c 1.16 1997/01/31 02:11:12 mohan Exp $" +#ident "$Id: scam.c 1.17 1997/03/20 23:49:37 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -9237,9 +9366,9 @@ * and the determination of the SCSI IDs to be assigned * to all perspective SCSI targets. * - * $Date: 1997/01/31 02:11:12 $ + * $Date: 1997/03/20 23:49:37 $ * - * $Revision: 1.16 $ + * $Revision: 1.17 $ * *----------------------------------------------------------------------*/ @@ -9468,7 +9597,7 @@ if (((ScamFlg & SCAM_ENABLED) && (scamInfo[i].state == LEGACY)) || (i != p_our_id)) { - scsell(p_port,i); + scsellDOS(p_port,i); } } #endif @@ -9885,6 +10014,7 @@ } if ((ret_data & 0x1F) == 0) + { /* if(bit_cnt != 0 || bit_cnt != 8) { @@ -9899,6 +10029,7 @@ return(0x00); else return(0xFF); + } } /*bit loop */ @@ -10090,6 +10221,90 @@ } } +#if defined(DOS) +/*--------------------------------------------------------------------- + * + * Function: scsell for DOS + * + * Description: Select the specified device ID using a selection timeout + * less than 2ms. This was specially required to solve + * the problem with Plextor 12X CD-ROM drive. This drive + * was responding the Selection at the end of 4ms and + * hanging the system. + * + *---------------------------------------------------------------------*/ + +UCHAR scsellDOS(USHORT p_port, UCHAR targ_id) +{ + USHORT i; + + WR_HARPOON(p_port+hp_page_ctrl, + (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE)); + + ARAM_ACCESS(p_port); + + WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) | SCAM_TIMER)); + WR_HARPOON(p_port+hp_seltimeout,TO_2ms); + + + for (i = p_port+CMD_STRT; i < p_port+CMD_STRT+12; i+=2) { + WRW_HARPOON(i, (MPM_OP+ACOMMAND)); + } + WRW_HARPOON(i, (BRH_OP+ALWAYS+ NP)); + + WRW_HARPOON((p_port+hp_intstat), + (RESET | TIMEOUT | SEL | BUS_FREE | AUTO_INT)); + + WR_HARPOON(p_port+hp_select_id, targ_id); + + WR_HARPOON(p_port+hp_portctrl_0, SCSI_PORT); + WR_HARPOON(p_port+hp_autostart_3, (SELECT | CMD_ONLY_STRT)); + WR_HARPOON(p_port+hp_scsictrl_0, (SEL_TAR | ENA_RESEL)); + + + while (!(RDW_HARPOON((p_port+hp_intstat)) & + (RESET | PROG_HLT | TIMEOUT | AUTO_INT))) {} + + if (RDW_HARPOON((p_port+hp_intstat)) & RESET) + Wait(p_port, TO_250ms); + + DISABLE_AUTO(p_port); + + WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) & ~SCAM_TIMER)); + WR_HARPOON(p_port+hp_seltimeout,TO_290ms); + + SGRAM_ACCESS(p_port); + + if (RDW_HARPOON((p_port+hp_intstat)) & (RESET | TIMEOUT) ) { + + WRW_HARPOON((p_port+hp_intstat), + (RESET | TIMEOUT | SEL | BUS_FREE | PHASE)); + + WR_HARPOON(p_port+hp_page_ctrl, + (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE)); + + return(FALSE); /*No legacy device */ + } + + else { + + while(!(RDW_HARPOON((p_port+hp_intstat)) & BUS_FREE)) { + if (RD_HARPOON(p_port+hp_scsisig) & SCSI_REQ) + { + WR_HARPOON(p_port+hp_scsisig, (SCSI_ACK + S_ILL_PH)); + ACCEPT_MSG(p_port); + } + } + + WRW_HARPOON((p_port+hp_intstat), CLR_ALL_INT_1); + + WR_HARPOON(p_port+hp_page_ctrl, + (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE)); + + return(TRUE); /*Found one of them oldies! */ + } +} +#endif /* DOS */ /*--------------------------------------------------------------------- * @@ -10252,10 +10467,12 @@ match--; if (match == 0xFF) + { if (p_id_string[0] & BIT(5)) match = 7; else match = MAX_SCSI_TAR-1; + } } @@ -10300,10 +10517,12 @@ match--; if (match == 0xFF) + { if (p_id_string[0] & BIT(5)) match = 7; else match = MAX_SCSI_TAR-1; + } } return(NO_ID_AVAIL); @@ -10362,7 +10581,7 @@ utilEEWrite(p_port, sum_data, EEPROM_CHECK_SUM/2); utilEEWriteOnOff(p_port,0); /* Turn off write access */ } -#ident "$Id: diagnose.c 1.9 1997/01/31 02:09:48 mohan Exp $" +#ident "$Id: diagnose.c 1.10 1997/06/10 16:51:47 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -10376,9 +10595,9 @@ * Description: Diagnostic funtions for testing the integrity of * the HARPOON. * - * $Date: 1997/01/31 02:09:48 $ + * $Date: 1997/06/10 16:51:47 $ * - * $Revision: 1.9 $ + * $Revision: 1.10 $ * *----------------------------------------------------------------------*/ @@ -10419,7 +10638,7 @@ WR_HARPOON(port+hp_scsireset,(DMA_RESET | HPSCSI_RESET | PROG_RESET | \ FIFO_CLR)); - WR_HARPOON(port+hp_scsireset,0x00); + WR_HARPOON(port+hp_scsireset,SCSI_INI); WR_HARPOON(port+hp_clkctrl_0,CLKCTRL_DEFAULT); @@ -10703,8 +10922,8 @@ temp += 0x70D3; utilEEWrite(p_port, 0x0010, BIOS_CONFIG/2); temp += 0x0010; - utilEEWrite(p_port, 0x0007, SCAM_CONFIG/2); - temp += 0x0007; + utilEEWrite(p_port, 0x0003, SCAM_CONFIG/2); + temp += 0x0003; utilEEWrite(p_port, 0x0007, ADAPTER_SCSI_ID/2); temp += 0x0007; @@ -10807,7 +11026,7 @@ } -#ident "$Id: utility.c 1.22 1997/01/31 02:12:23 mohan Exp $" +#ident "$Id: utility.c 1.23 1997/06/10 16:55:06 mohan Exp $" /*---------------------------------------------------------------------- * * @@ -10821,9 +11040,9 @@ * Description: Utility functions relating to queueing and EEPROM * manipulation and any other garbage functions. * - * $Date: 1997/01/31 02:12:23 $ + * $Date: 1997/06/10 16:55:06 $ * - * $Revision: 1.22 $ + * $Revision: 1.23 $ * *----------------------------------------------------------------------*/ /*#include */ @@ -11617,10 +11836,13 @@ ee_value &= ~SEE_DO; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value |= SEE_CLK; /* Clock data! */ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value &= ~SEE_CLK; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); } ee_value &= (EXT_ARB_ACK | SCSI_TERM_ENA_H); WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS)); @@ -11632,7 +11854,6 @@ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); /* Turn off Master Select */ } - /*--------------------------------------------------------------------- * * Function: Read EEPROM @@ -11648,6 +11869,40 @@ USHORT utilEERead(ULONG p_port, USHORT ee_addr) #endif { + USHORT i, ee_data1, ee_data2; + + i = 0; + ee_data1 = utilEEReadOrg(p_port, ee_addr); + do + { + ee_data2 = utilEEReadOrg(p_port, ee_addr); + + if(ee_data1 == ee_data2) + return(ee_data1); + + ee_data1 = ee_data2; + i++; + + }while(i < 4); + + return(ee_data1); +} + +/*--------------------------------------------------------------------- + * + * Function: Read EEPROM Original + * + * Description: Read a word from the EEPROM at the desired + * address. + * + *---------------------------------------------------------------------*/ + +#if defined(DOS) +USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr) +#else +USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr) +#endif +{ UCHAR ee_value; USHORT i, ee_data; @@ -11666,8 +11921,10 @@ ee_value |= SEE_CLK; /* Clock data! */ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value &= ~SEE_CLK; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_data <<= 1; @@ -11722,10 +11979,13 @@ ee_value &= ~SEE_DO; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value |= SEE_CLK; /* Clock data! */ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value &= ~SEE_CLK; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); } @@ -11744,10 +12004,13 @@ ee_value &= ~SEE_DO; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value |= SEE_CLK; /* Clock data! */ WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); ee_value &= ~SEE_CLK; WR_HARPOON(p_port+hp_ee_ctrl, ee_value); + WR_HARPOON(p_port+hp_ee_ctrl, ee_value); i >>= 1; } @@ -11783,6 +12046,114 @@ return(lrc); } + + +/* + The following inline definitions avoid type conflicts. +*/ + +static inline unsigned char +FlashPoint__ProbeHostAdapter(FlashPoint_Info_T *FlashPointInfo) +{ + return FlashPoint_ProbeHostAdapter((PSCCBMGR_INFO) FlashPointInfo); +} + + +static inline FlashPoint_CardHandle_T +FlashPoint__HardwareResetHostAdapter(FlashPoint_Info_T *FlashPointInfo) +{ + return FlashPoint_HardwareResetHostAdapter((PSCCBMGR_INFO) FlashPointInfo); +} + +static inline void +FlashPoint__ReleaseHostAdapter(FlashPoint_CardHandle_T CardHandle) +{ + FlashPoint_ReleaseHostAdapter(CardHandle); +} + + +static inline void +FlashPoint__StartCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB) +{ + FlashPoint_StartCCB(CardHandle, (PSCCB) CCB); +} + + +static inline void +FlashPoint__AbortCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB) +{ + FlashPoint_AbortCCB(CardHandle, (PSCCB) CCB); +} + + +static inline boolean +FlashPoint__InterruptPending(FlashPoint_CardHandle_T CardHandle) +{ + return FlashPoint_InterruptPending(CardHandle); +} + + +static inline int +FlashPoint__HandleInterrupt(FlashPoint_CardHandle_T CardHandle) +{ + return FlashPoint_HandleInterrupt(CardHandle); +} + + +#define FlashPoint_ProbeHostAdapter FlashPoint__ProbeHostAdapter +#define FlashPoint_HardwareResetHostAdapter FlashPoint__HardwareResetHostAdapter +#define FlashPoint_ReleaseHostAdapter FlashPoint__ReleaseHostAdapter +#define FlashPoint_StartCCB FlashPoint__StartCCB +#define FlashPoint_AbortCCB FlashPoint__AbortCCB +#define FlashPoint_InterruptPending FlashPoint__InterruptPending +#define FlashPoint_HandleInterrupt FlashPoint__HandleInterrupt + + +/* + FlashPoint_InquireTargetInfo returns the Synchronous Period, Synchronous + Offset, and Wide Transfers Active information for TargetID on CardHandle. +*/ + +void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T CardHandle, + int TargetID, + unsigned char *SynchronousPeriod, + unsigned char *SynchronousOffset, + unsigned char *WideTransfersActive) +{ + SCCBMGR_TAR_INFO *TargetInfo = + &sccbMgrTbl[((SCCBCARD *)CardHandle)->cardIndex][TargetID]; + if ((TargetInfo->TarSyncCtrl & SYNC_OFFSET) > 0) + { + *SynchronousPeriod = 5 * ((TargetInfo->TarSyncCtrl >> 5) + 1); + *SynchronousOffset = TargetInfo->TarSyncCtrl & SYNC_OFFSET; + } + else + { + *SynchronousPeriod = 0; + *SynchronousOffset = 0; + } + *WideTransfersActive = (TargetInfo->TarSyncCtrl & NARROW_SCSI ? 0 : 1); +} + + +#else /* CONFIG_SCSI_OMIT_FLASHPOINT */ + + +/* + Define prototypes for the FlashPoint SCCB Manager Functions. +*/ + +extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *); +extern FlashPoint_CardHandle_T + FlashPoint_HardwareResetHostAdapter(FlashPoint_Info_T *); +extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *); +extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *); +extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T); +extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T); +extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T); +extern void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T, + int, unsigned char *, + unsigned char *, unsigned char *); #endif /* CONFIG_SCSI_OMIT_FLASHPOINT */ diff -ur --new-file old/linux/drivers/scsi/Makefile new/linux/drivers/scsi/Makefile --- old/linux/drivers/scsi/Makefile Mon Jan 5 10:41:01 1998 +++ new/linux/drivers/scsi/Makefile Fri Feb 13 00:48:43 1998 @@ -430,6 +430,14 @@ endif endif +ifeq ($(CONFIG_SCSI_PLUTO),y) +L_OBJS += pluto.o +else + ifeq ($(CONFIG_SCSI_PLUTO),m) + M_OBJS += pluto.o + endif +endif + ifeq ($(CONFIG_SCSI_EATA),y) L_OBJS += eata.o else @@ -455,14 +463,6 @@ endif include $(TOPDIR)/Rules.make - -# This gives correct output but uses old-style "excessive compilation". -# This will be fixed soon (about December 1997 or January 1998). -BusLogic.o: BusLogic.c FlashPoint.c ../../include/linux/autoconf.h - $(CC) $(CFLAGS) -c BusLogic.c -o BusLogic.O - $(CC) $(CFLAGS) -c FlashPoint.c -o FlashPoint.O - $(LD) -r -o BusLogic.o BusLogic.O FlashPoint.O - rm -f BusLogic.O FlashPoint.O 53c8xx_d.h 53c8xx_u.h : 53c7,8xx.scr script_asm.pl ln -sf 53c7,8xx.scr fake.c diff -ur --new-file old/linux/drivers/scsi/NCR5380.c new/linux/drivers/scsi/NCR5380.c --- old/linux/drivers/scsi/NCR5380.c Thu Apr 24 04:01:21 1997 +++ new/linux/drivers/scsi/NCR5380.c Sun Jan 25 19:05:46 1998 @@ -625,7 +625,8 @@ */ -static int probe_irq __initdata; +static int probe_irq __initdata = 0; + __initfunc(static void probe_intr (int irq, void *dev_id, struct pt_regs * regs)) { probe_irq = irq; }; diff -ur --new-file old/linux/drivers/scsi/NCR53c406a.c new/linux/drivers/scsi/NCR53c406a.c --- old/linux/drivers/scsi/NCR53c406a.c Thu Apr 24 04:01:21 1997 +++ new/linux/drivers/scsi/NCR53c406a.c Sat Jan 24 02:38:04 1998 @@ -1012,7 +1012,7 @@ outb(SYNC_MODE, SYNCOFF); /* synchronous mode */ } -__initfunc(void calc_port_addr()) +__initfunc(void calc_port_addr(void)) { /* Control Register Set 0 */ TC_LSB = (port_base+0x00); diff -ur --new-file old/linux/drivers/scsi/README.BusLogic new/linux/drivers/scsi/README.BusLogic --- old/linux/drivers/scsi/README.BusLogic Mon Aug 11 09:10:00 1997 +++ new/linux/drivers/scsi/README.BusLogic Sat Jan 31 11:00:00 1998 @@ -1,10 +1,10 @@ BusLogic MultiMaster and FlashPoint SCSI Driver for Linux - Version 2.0.10 for Linux 2.0 + Version 2.0.11 for Linux 2.0 PRODUCTION RELEASE - 11 August 1997 + 31 January 1998 Leonard N. Zubkoff Dandelion Digital @@ -15,27 +15,34 @@ INTRODUCTION -BusLogic, Inc. designs and manufactures a variety of high performance SCSI host -adapters which share a common programming interface across a diverse collection -of bus architectures by virtue of their MultiMaster ASIC technology. This -driver supports all present BusLogic MultiMaster Host Adapters, and should +BusLogic, Inc. designed and manufactured a variety of high performance SCSI +host adapters which share a common programming interface across a diverse +collection of bus architectures by virtue of their MultiMaster ASIC technology. +BusLogic was acquired by Mylex Corporation in February 1996, but the products +supported by this driver originated under the BusLogic name and so that name is +retained in the source code and documentation. + +This driver supports all present BusLogic MultiMaster Host Adapters, and should support any future MultiMaster designs with little or no modification. More -recently, BusLogic has introduced the FlashPoint Host Adapters, which are less +recently, BusLogic introduced the FlashPoint Host Adapters, which are less costly and rely on the host CPU, rather than including an onboard processor. -Mylex/BusLogic has recently provided me with the FlashPoint Driver Developer's -Kit, which comprises documentation and freely redistributable source code for -the FlashPoint SCCB Manager. The SCCB Manager is the library of code that runs -on the host CPU and performs functions analogous to the firmware on the -MultiMaster Host Adapters. Thanks to their having provided the SCCB Manager, -this driver now supports the FlashPoint Host Adapters as well. +Despite not having an onboard CPU, the FlashPoint Host Adapters perform very +well and have very low command latency. BusLogic has recently provided me with +the FlashPoint Driver Developer's Kit, which comprises documentation and freely +redistributable source code for the FlashPoint SCCB Manager. The SCCB Manager +is the library of code that runs on the host CPU and performs functions +analogous to the firmware on the MultiMaster Host Adapters. Thanks to their +having provided the SCCB Manager, this driver now supports the FlashPoint Host +Adapters as well. My primary goals in writing this completely new BusLogic driver for Linux are to achieve the full performance that BusLogic SCSI Host Adapters and modern SCSI peripherals are capable of, and to provide a highly robust driver that can be depended upon for high performance mission critical applications. All of the major performance and error recovery features can be configured from the -Linux kernel command line, allowing individual installations to tune driver -performance and error recovery to their particular needs. +Linux kernel command line or at module initialization time, allowing individual +installations to tune driver performance and error recovery to their particular +needs. The latest information on Linux support for BusLogic SCSI Host Adapters, as well as the most recent release of this driver and the latest firmware for the @@ -48,33 +55,35 @@ relevant to SCSI operations, and a detailed description of your system's hardware configuration. -BusLogic has been an excellent company to work with and I highly recommend -their products to the Linux community. In November 1995, I was offered the +Mylex has been an excellent company to work with and I highly recommend their +products to the Linux community. In November 1995, I was offered the opportunity to become a beta test site for their latest MultiMaster product, the BT-948 PCI Ultra SCSI Host Adapter, and then again for the BT-958 PCI Wide Ultra SCSI Host Adapter in January 1996. This was mutually beneficial since -BusLogic received a degree and kind of testing that their own testing group -cannot readily achieve, and the Linux community has available high performance -host adapters that have been well tested with Linux even before being brought -to market. This relationship has also given me the opportunity to interact +Mylex received a degree and kind of testing that their own testing group cannot +readily achieve, and the Linux community has available high performance host +adapters that have been well tested with Linux even before being brought to +market. This relationship has also given me the opportunity to interact directly with their technical staff, to understand more about the internal workings of their products, and in turn to educate them about the needs and -potential of the Linux community. Their interest and support is greatly -appreciated. +potential of the Linux community. + +More recently, Mylex has reaffirmed the company's interest in supporting the +Linux community, and I am now working on a Linux driver for the DAC960 PCI RAID +Controllers. Mylex's interest and support is greatly appreciated. -Unlike some other vendors, if you contact BusLogic Technical Support with a +Unlike some other vendors, if you contact Mylex Technical Support with a problem and are running Linux, they will not tell you that your use of their products is unsupported. Their latest product marketing literature even states -"BusLogic SCSI host adapters are compatible with all major operating systems +"Mylex SCSI host adapters are compatible with all major operating systems including: ... Linux ...". -BusLogic, Inc. is located at 4151 Burton Drive, Santa Clara, California, 95054, -USA and can be reached by Voice at 408/492-9090 or by FAX at 408/492-1542. -BusLogic maintains a World Wide Web site at http://www.buslogic.com, an -anonymous FTP site at ftp.buslogic.com, and a BBS at 408/492-1984. BusLogic -Technical Support can be reached by electronic mail at techsup@buslogic.com, by -Voice at 408/654-0760, or by FAX at 408/492-1542. Contact information for -offices in Europe and Japan is available on the Web site. +Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont, California +94555, USA and can be reached at 510/796-6100 or on the World Wide Web at +http://www.mylex.com. Mylex Technical Support can be reached by electronic +mail at techsup@mylex.com, by Voice at 510/608-2400, or by FAX at 510/745-7715. +Contact information for offices in Europe and Japan is available on the Web +site. DRIVER FEATURES @@ -83,15 +92,46 @@ During system initialization, the driver reports extensively on the host adapter hardware configuration, including the synchronous transfer parameters - negotiated with each target device. In addition, the driver tests the - hardware interrupt configuration to verify that interrupts are actually - delivered correctly to the interrupt handler. This should catch a high - percentage of PCI motherboard configuration errors early, because when the - host adapter is probed successfully, most of the remaining problems appear to - be related to interrupts. Most often, any remaining hardware problems are - related to the specific configuration of devices on the SCSI bus, and the - quality of cabling and termination used. Finally, this BusLogic driver - should never incorrectly attempt to support an Adaptec 154x Host Adapter. + requested and negotiated with each target device. AutoSCSI settings for + Synchronous Negotiation, Wide Negotiation, and Disconnect/Reconnect are + reported for each target device, as well as the status of Tagged Queuing and + Error Recovery. If the same setting is in effect for all target devices, + then a single word or phrase is used; otherwise, a letter is provided for + each target device to indicate the individual status. The following examples + should clarify this reporting format: + + Synchronous Negotiation: Ultra + + Synchronous negotiation is enabled for all target devices and the host + adapter will attempt to negotiate for 20.0 mega-transfers/second. + + Synchronous Negotiation: Fast + + Synchronous negotiation is enabled for all target devices and the host + adapter will attempt to negotiate for 10.0 mega-transfers/second. + + Synchronous Negotiation: Slow + + Synchronous negotiation is enabled for all target devices and the host + adapter will attempt to negotiate for 5.0 mega-transfers/second. + + Synchronous Negotiation: Disabled + + Synchronous negotiation is disabled and all target devices are limited to + asynchronous operation. + + Synchronous Negotiation: UFSNUUU#UUUUUUUU + + Synchronous negotiation to Ultra speed is enabled for target devices 0 + and 4 through 15, to Fast speed for target device 1, to Slow speed for + target device 2, and is not permitted to target device 3. The host + adapter's SCSI ID is represented by the "#". + + The status of Wide Negotiation, Disconnect/Reconnect, and Tagged Queuing + are reported as "Enabled", Disabled", or a sequence of "Y" and "N" letters. + + The Error Recovery option is reported as "Default", "Hard Reset", + "Bus Device Reset", "None" or a sequence of "D", "H", "B", and "N" letters. o Performance Features @@ -103,16 +143,15 @@ addition, BusLogic's Strict Round Robin Mode is used to optimize host adapter performance, and scatter/gather I/O can support as many segments as can be effectively utilized by the Linux I/O subsystem. Control over the use of - tagged queuing for each target device as well as selection of the tagged - queue depth is available from the kernel command line. By default, the queue - depth is automatically determined based on the number, type, speed, and - capabilities of the target devices found. In addition, tagged queuing is - automatically disabled whenever the host adapter firmware version is known - not to implement it correctly, or whenever a tagged queue depth of 1 is - selected. Tagged queuing is also disabled for individual target devices if - disconnect/reconnect is disabled for that device. In performance testing, - sustained disk writes of 7.3MB per second have been observed to a /dev/sd - device. + tagged queuing for each target device as well as individual selection of the + tagged queue depth is available through driver options provided on the kernel + command line or at module initialization time. By default, the queue depth + is determined automatically based on the host adapter's total queue depth and + the number, type, speed, and capabilities of the target devices found. In + addition, tagged queuing is automatically disabled whenever the host adapter + firmware version is known not to implement it correctly, or whenever a tagged + queue depth of 1 is selected. Tagged queuing is also disabled for individual + target devices if disconnect/reconnect is disabled for that device. o Robustness Features @@ -121,15 +160,15 @@ a selection is made between a full host adapter hard reset and SCSI bus reset versus sending a bus device reset message to the individual target device based on the recommendation of the SCSI subsystem. Error recovery strategies - are selectable from the kernel command line individually for each target - device, and also include sending a bus device reset to the specific target - device associated with the command being reset, as well as suppressing error + are selectable through driver options individually for each target device, + and also include sending a bus device reset to the specific target device + associated with the command being reset, as well as suppressing error recovery entirely to avoid perturbing an improperly functioning device. If the bus device reset error recovery strategy is selected and sending a bus device reset does not restore correct operation, the next command that is reset will force a full host adapter hard reset and SCSI bus reset. SCSI bus resets caused by other devices and detected by the host adapter are also - handled by issuing a hard reset to the host adapter and re-initialization. + handled by issuing a soft reset to the host adapter and re-initialization. Finally, if tagged queuing is active and more than one command reset occurs in a 10 minute interval, or if a command reset occurs within the first 10 minutes of operation, then tagged queuing will be disabled for that target @@ -138,15 +177,6 @@ lock up or crash, and thereby allowing a clean shutdown and restart after the offending component is removed. -o Extensive Testing - - This driver has undergone extensive testing and improvement over a period of - several months, and is routinely being used on heavily loaded systems. Over - 300 people retrieved the driver during the beta test period. In addition to - testing in normal system operation, error recovery tests have been performed - to verify proper system recovery in the case of simulated dropped interrupts, - external SCSI bus resets, and SCSI command errors due to bad CD-ROM media. - o PCI Configuration Support On PCI systems running kernels compiled with PCI BIOS support enabled, this @@ -159,8 +189,8 @@ o /proc File System Support - Copies of the host adapter configuration information together with data - transfer and error recovery statistics are now available through the + Copies of the host adapter configuration information together with updated + data transfer and error recovery statistics are available through the /proc/scsi/BusLogic/ interface. o Shared Interrupts Support @@ -168,16 +198,6 @@ On systems that support shared interrupts, any number of BusLogic Host Adapters may share the same interrupt request channel. -o Wide SCSI Support - - All BusLogic MultiMaster SCSI Host Adapters share a common programming - interface, except for the inevitable improvements and extensions as new - models are released, so support for Wide SCSI data transfer has automatically - been available without explicit driver support. When used with Linux 2.0.x, - this driver adds explicit support for up to 15 target devices and 64 logical - units per target device, to fully exploit the capabilities of the newest - BusLogic Wide SCSI Host Adapters. - SUPPORTED HOST ADAPTERS @@ -188,16 +208,21 @@ FlashPoint Series PCI Host Adapters: -FlashPoint LT (BT-930) Ultra SCSI-2 -FlashPoint DL (BT-932) Dual Channel Ultra SCSI-2 -FlashPoint LW (BT-950) Wide Ultra SCSI-2 -FlashPoint DW (BT-952) Dual Channel Wide Ultra SCSI-2 +FlashPoint LT (BT-930) Ultra SCSI-3 +FlashPoint LT (BT-930R) Ultra SCSI-3 with RAIDPlus +FlashPoint LT (BT-920) Ultra SCSI-3 (BT-930 without BIOS) +FlashPoint DL (BT-932) Dual Channel Ultra SCSI-3 +FlashPoint DL (BT-932R) Dual Channel Ultra SCSI-3 with RAIDPlus +FlashPoint LW (BT-950) Wide Ultra SCSI-3 +FlashPoint LW (BT-950R) Wide Ultra SCSI-3 with RAIDPlus +FlashPoint DW (BT-952) Dual Channel Wide Ultra SCSI-3 +FlashPoint DW (BT-952R) Dual Channel Wide Ultra SCSI-3 with RAIDPlus MultiMaster "W" Series Host Adapters: -BT-948 PCI Ultra SCSI-2 -BT-958 PCI Wide Ultra SCSI-2 -BT-958D PCI Wide Differential Ultra SCSI-2 +BT-948 PCI Ultra SCSI-3 +BT-958 PCI Wide Ultra SCSI-3 +BT-958D PCI Wide Differential Ultra SCSI-3 MultiMaster "C" Series Host Adapters: @@ -231,6 +256,39 @@ AMI FastDisk Host Adapters that are true BusLogic MultiMaster clones are also supported by this driver. +BusLogic SCSI Host Adapters are available packaged both as bare boards and as +retail kits. The BT- model numbers above refer to the bare board packaging. +The retail kit model numbers are found by replacing BT- with KT- in the above +list. The retail kit includes the bare board and manual as well as cabling and +driver media and documentation that are not provided with bare boards. + + + FLASHPOINT INSTALLATION NOTES + +o RAIDPlus Support + + FlashPoint Host Adapters now include RAIDPlus, Mylex's bootable software + RAID. RAIDPlus is not supported on Linux, and there are no plans to support + it. The MD driver in Linux 2.0 provides for concatenation (LINEAR) and + striping (RAID-0), and support for mirroring (RAID-1), fixed parity (RAID-4), + and distributed parity (RAID-5) is available separately. The built-in Linux + RAID support is generally more flexible and is expected to perform better + than RAIDPlus, so there is little impetus to include RAIDPlus support in the + BusLogic driver. + +o Enabling UltraSCSI Transfers + + FlashPoint Host Adapters ship with their configuration set to "Factory + Default" settings that are conservative and do not allow for UltraSCSI speed + to be negotiated. This results in fewer problems when these host adapters + are installed in systems with cabling or termination that is not sufficient + for UltraSCSI operation, or where existing SCSI devices do not properly + respond to synchronous transfer negotiation for UltraSCSI speed. AutoSCSI + may be used to load "Optimum Performance" settings which allow UltraSCSI + speed to be negotiated with all devices, or UltraSCSI speed can be enabled on + an individual basis. It is recommended that SCAM be manually disabled after + the "Optimum Performance" settings are loaded. + BT-948/958/958D INSTALLATION NOTES @@ -284,113 +342,254 @@ so as to recognize the host adapters in the same order as they are enumerated by the host adapter's BIOS. -o Mega-Transfers/Second +o Enabling UltraSCSI Transfers + + The BT-948/958/958D ship with their configuration set to "Factory Default" + settings that are conservative and do not allow for UltraSCSI speed to be + negotiated. This results in fewer problems when these host adapters are + installed in systems with cabling or termination that is not sufficient for + UltraSCSI operation, or where existing SCSI devices do not properly respond + to synchronous transfer negotiation for UltraSCSI speed. AutoSCSI may be + used to load "Optimum Performance" settings which allow UltraSCSI speed to be + negotiated with all devices, or UltraSCSI speed can be enabled on an + individual basis. It is recommended that SCAM be manually disabled after the + "Optimum Performance" settings are loaded. + + + DRIVER OPTIONS + +BusLogic Driver Options may be specified either via the Linux Kernel Command +Line or via the Loadable Kernel Module Installation Facility. Driver Options +for multiple host adapters may be specified either by separating the option +strings by a semicolon, or by specifying multiple "BusLogic=" strings on the +command line. Individual option specifications for a single host adapter are +separated by commas. The Probing and Debugging Options apply to all host +adapters whereas the remaining options apply individually only to the +selected host adapter. + +The BusLogic Driver Probing Options comprise the following: + +IO: + + The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI + MultiMaster Host Adapter. If neither "IO:" nor "NoProbeISA" options are + specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses + will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134). Multiple + "IO:" options may be specified to precisely determine the I/O Addresses to + be probed, but the probe order will always follow the standard list. + +NoProbe + + The "NoProbe" option disables all probing and therefore no BusLogic Host + Adapters will be detected. + +NoProbeISA + + The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O + Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters + will be detected. - The driver reports on the synchronous transfer parameters negotiated between - the host adapter and target devices in units of "mega-transfers/second". For - wide devices, the unit of transfer is 16 bits if wide negotiation has been - successfully completed. Therefore, the total transfer rate to wide devices - will generally be twice the synchronous tranfer rate reported by the driver. +NoProbePCI + The "NoProbePCI" options disables the interrogation of PCI Configuration + Space and therefore only ISA Multimaster Host Adapters will be detected, as + well as PCI Multimaster Host Adapters that have their ISA Compatible I/O + Port set to "Primary" or "Alternate". - COMMAND LINE OPTIONS +NoSortPCI -Many features of this driver are configurable by specification of appropriate -kernel command line options. A full description of the command line options -may be found in the comments before BusLogic_Setup in the kernel source code -file "BusLogic.c". The following examples may be useful as a starting point: + The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be + enumerated in the order provided by the PCI BIOS, ignoring any setting of + the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option. - "BusLogic=NoProbe" +MultiMasterFirst - No probing of any kind is to be performed, and hence no BusLogic Host - Adapters will be detected. + The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed + before FlashPoint Host Adapters. By default, if both FlashPoint and PCI + MultiMaster Host Adapters are present, this driver will probe for + FlashPoint Host Adapters first unless the BIOS primary disk is controlled + by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host + Adapters will be probed first. - "BusLogic=NoProbeISA" +FlashPointFirst - No probing of the standard ISA I/O Addresses will be done, and hence only - PCI Host Adapters will be detected. + The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed + before MultiMaster Host Adapters. - "BusLogic=NoProbePCI" +The BusLogic Driver Tagged Queuing Options allow for explicitly specifying +the Queue Depth and whether Tagged Queuing is permitted for each Target +Device (assuming that the Target Device supports Tagged Queuing). The Queue +Depth is the number of SCSI Commands that are allowed to be concurrently +presented for execution (either to the Host Adapter or Target Device). Note +that explicitly enabling Tagged Queuing may lead to problems; the option to +enable or disable Tagged Queuing is provided primarily to allow disabling +Tagged Queuing on Target Devices that do not implement it correctly. The +following options are available: - No interrogation of PCI Configuration Space will be made, and hence only - ISA Multimaster Host Adapters will be detected, as well as PCI Multimaster - Host Adapters that have their ISA Compatible I/O Port set to "Primary" or - "Alternate". +QueueDepth: - "BusLogic=NoSortPCI" + The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all + Target Devices that support Tagged Queuing. If no Queue Depth option is + provided, the Queue Depth will be determined automatically based on the + Host Adapter's Total Queue Depth and the number, type, speed, and + capabilities of the detected Target Devices. For Host Adapters that + require ISA Bounce Buffers, the Queue Depth is automatically set by default + to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA + Bounce Buffer memory. Target Devices that do not support Tagged Queuing + always use a Queue Depth of BusLogic_UntaggedQueueDepth. - PCI MultiMaster Host Adapters will be enumerated in the order provided by - the PCI BIOS, ignoring any setting of the AutoSCSI "Use Bus And Device # - For PCI Scanning Seq." option. +QueueDepth:[,...] - "BusLogic=MultiMasterFirst" + The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth + individually for each Target Device. If an is omitted, the + associated Target Device will have its Queue Depth selected automatically. - By default, if both FlashPoint and PCI MultiMaster Host Adapters are - present, this driver will probe for FlashPoint Host Adapters first unless - the BIOS primary disk is controlled by the first PCI MultiMaster Host - Adapter, in which case MultiMaster Host Adapters will be probed first. - This option forces MultiMaster Host Adapters to be probed first. +TaggedQueuing:Default - "BusLogic=FlashPointFirst" + The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing + based on the firmware version of the BusLogic Host Adapter and based on + whether the Queue Depth allows queuing multiple commands. - By default, if both FlashPoint and PCI MultiMaster Host Adapters are - present, this driver will probe for FlashPoint Host Adapters first unless - the BIOS primary disk is controlled by the first PCI MultiMaster Host - Adapter, in which case MultiMaster Host Adapters will be probed first. - This option forces FlashPoint Host Adapters to be probed first. +TaggedQueuing:Enable - "BusLogic=0x330" + The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for + all Target Devices on this Host Adapter, overriding any limitation that + would otherwise be imposed based on the Host Adapter firmware version. - This command line limits probing to the single I/O port at 0x330. +TaggedQueuing:Disable - "BusLogic=0,1" + The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing + for all Target Devices on this Host Adapter. - This command line selects default probing and a tagged queue depth of 1 - which also disables tagged queuing. It may be useful if problems arise - during installation on a system with a flaky SCSI configuration. In cases - of a marginal SCSI configuration it may also be beneficial to disable fast - transfers and/or synchronous negotiation using AutoSCSI on FlashPoint and - "W" and "C" series MultiMaster host adapters. Disconnect/reconnect may - also be disabled for fast devices such as disk drives, but should not be - disabled for tape drives or other devices where a single command may take - over a second to execute. +TaggedQueuing: - "BusLogic=0,0,30" + The "TaggedQueuing:" or "TQ:" option controls + Tagged Queuing individually for each Target Device. is a + sequence of "Y", "N", and "X" characters. "Y" enables Tagged Queuing, "N" + disables Tagged Queuing, and "X" accepts the default based on the firmware + version. The first character refers to Target Device 0, the second to + Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters + does not cover all the Target Devices, unspecified characters are assumed + to be "X". - This command line selects default probing and automatic tagged queue depth - selection, but changes the bus settle time to 30 seconds. It may be useful - with SCSI devices that take an unusually long time to become ready to - accept commands after a SCSI bus reset. Some tape drives will not respond - properly immediately after a SCSI bus reset, especially if a tape is - present in the drive. +The BusLogic Driver Error Recovery Option allows for explicitly specifying +the Error Recovery action to be performed when BusLogic_ResetCommand is +called due to a SCSI Command failing to complete successfully. The following +options are available: - "BusLogic=TQ:Disable" +ErrorRecovery:Default - This command line selects default probing and disables tagged queuing. + The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard + Reset and Bus Device Reset options based on the recommendation of the SCSI + Subsystem. - "BusLogic=0,15,TQ:N" +ErrorRecovery:HardReset - This command line selects a tagged queue depth of 15 and disables tagged - queuing for target 0, while allowing tagged queuing for all other target - devices. + The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host + Adapter Hard Reset which also causes a SCSI Bus Reset. -Note that limiting the tagged queue depth or disabling tagged queuing can -substantially impact performance. +ErrorRecovery:BusDeviceReset + The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send + a Bus Device Reset message to the individual Target Device causing the + error. If Error Recovery is again initiated for this Target Device and no + SCSI Command to this Target Device has completed successfully since the Bus + Device Reset message was sent, then a Hard Reset will be attempted. - INSTALLATION +ErrorRecovery:None -This distribution was prepared for Linux kernel version 2.0.30, but should be -compatible with 2.0.4 or any later 2.0 series kernel if BusLogic.patch is also -applied. + The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery. + This option should only be selected if a SCSI Bus Reset or Bus Device Reset + will cause the Target Device or a critical operation to suffer a complete + and unrecoverable failure. + +ErrorRecovery: + + The "ErrorRecovery:" or "ER:" option controls + Error Recovery individually for each Target Device. is a + sequence of "D", "H", "B", and "N" characters. "D" selects Default, "H" + selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None. + The first character refers to Target Device 0, the second to Target Device + 1, and so on; if the sequence of "D", "H", "B", and "N" characters does not + cover all the possible Target Devices, unspecified characters are assumed + to be "D". + +The BusLogic Driver Miscellaneous Options comprise the following: + +BusSettleTime: + + The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in + seconds. The Bus Settle Time is the amount of time to wait between a Host + Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI + Commands. If unspecified, it defaults to BusLogic_DefaultBusSettleTime. + +InhibitTargetInquiry + + The "InhibitTargetInquiry" option inhibits the execution of an Inquire + Target Devices or Inquire Installed Devices command on MultiMaster Host + Adapters. This may be necessary with some older Target Devices that do not + respond correctly when Logical Units above 0 are addressed. + +The BusLogic Driver Debugging Options comprise the following: + +TraceProbe + + The "TraceProbe" option enables tracing of Host Adapter Probing. + +TraceHardwareReset + + The "TraceHardwareReset" option enables tracing of Host Adapter Hardware + Reset. + +TraceConfiguration + + The "TraceConfiguration" option enables tracing of Host Adapter + Configuration. + +TraceErrors + + The "TraceErrors" option enables tracing of SCSI Commands that return an + error from the Target Device. The CDB and Sense Data will be printed for + each SCSI Command that fails. + +Debug + + The "Debug" option enables all debugging options. + +The following examples demonstrate setting the Queue Depth for Target Devices +1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target +Devices on the second host adapter to 31, and the Bus Settle Time on the +second host adapter to 30 seconds. + +Linux Kernel Command Line: + + linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30 + +LILO Linux Boot Loader (in /etc/lilo.conf): + + append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30" + +INSMOD Loadable Kernel Module Installation Facility: + + insmod BusLogic.o \ + 'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"' + +NOTE: Module Utilities 2.1.71 or later is required for correct parsing + of driver options containing commas. + + + DRIVER INSTALLATION + +This distribution was prepared for Linux kernel version 2.0.33, but should be +compatible with 2.0.4 or any later 2.0 series kernel. To install the new BusLogic SCSI driver, you may use the following commands, replacing "/usr/src" with wherever you keep your Linux kernel source tree: cd /usr/src - tar -xvzf BusLogic-2.0.10.tar.gz + tar -xvzf BusLogic-2.0.11.tar.gz mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi - patch -p < BusLogic.patch # Only for kernels prior to 2.0.30 + patch -p < BusLogic.patch cd linux make config make depend @@ -398,11 +597,6 @@ Then install "arch/i386/boot/zImage" as your standard kernel, run lilo if appropriate, and reboot. - -Be sure to answer "y" to the "BusLogic SCSI support" query during the "make -config" step. If your system was already configured for the old BusLogic -driver or for an older version of this driver, you may omit the "make config" -step above. BUSLOGIC ANNOUNCEMENTS MAILING LIST diff -ur --new-file old/linux/drivers/scsi/README.Mylex new/linux/drivers/scsi/README.Mylex --- old/linux/drivers/scsi/README.Mylex Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/README.Mylex Sat Jan 31 11:00:00 1998 @@ -0,0 +1,6 @@ +Please see the file README.BusLogic for information about Linux support for +Mylex (formerly BusLogic) MultiMaster and FlashPoint SCSI Host Adapters. + +The Mylex DAC960 PCI RAID Controllers are not supported at the present time, +but work on a Linux driver for the DAC960 is in progress. Please consult +http://www.dandelion.com/Linux/ for further information on the DAC960 driver. diff -ur --new-file old/linux/drivers/scsi/README.ncr53c8xx new/linux/drivers/scsi/README.ncr53c8xx --- old/linux/drivers/scsi/README.ncr53c8xx Tue Jan 13 00:05:27 1998 +++ new/linux/drivers/scsi/README.ncr53c8xx Wed Feb 25 07:08:01 1998 @@ -941,7 +941,7 @@ Change to linux source directory Configure with NCR53C7,8XX support = N Configure with NCR53C8XX support = Y (or m) - Make dependancies + Make dependencies Make the kernel (use make zdisk first) Make and install modules if you have configured with 'm' diff -ur --new-file old/linux/drivers/scsi/advansys.c new/linux/drivers/scsi/advansys.c --- old/linux/drivers/scsi/advansys.c Mon Dec 22 02:04:48 1997 +++ new/linux/drivers/scsi/advansys.c Thu Feb 5 20:21:54 1998 @@ -1,10 +1,10 @@ -/* $Id: advansys.c,v 1997/05/28 00:06:55 bobf Exp bobf $ */ -#define ASC_VERSION "2.8" /* AdvanSys Driver Version */ +/* $Id: advansys.c,v 1.49 1998/01/22 20:19:25 bobf Exp bobf $ */ +#define ASC_VERSION "3.1D" /* AdvanSys Driver Version */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * - * Copyright (c) 1995-1997 Advanced System Products, Inc. + * Copyright (c) 1995-1998 Advanced System Products, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -16,13 +16,12 @@ * http://www.advansys.com/linux.html * * The latest version of the AdvanSys driver is available at: - * ftp://ftp.advansys.com/pub/linux + * ftp://ftp.advansys.com/pub/linux/linux.tgz * * Please send questions, comments, bug reports to: - * bobf@advansys.com (Bob Frey) + * bobf@advansys.com (Bob Frey) */ - /* Documentation for the AdvanSys Driver @@ -43,7 +42,7 @@ A. Linux Kernel Testing This driver has been tested in the following Linux kernels: v1.2.13, - v1.3.57, v2.0.30, v2.1.40. These kernel versions are major releases + v1.3.57, v2.0.33, v2.1.77. These kernel versions are major releases of Linux or the latest Linux kernel versions available when this version of the driver was released. The driver should also work in earlier versions of the Linux kernel. Beginning with v1.3.58 the AdvanSys driver @@ -53,8 +52,10 @@ B. Adapters Supported by this Driver AdvanSys (Advanced System Products, Inc.) manufactures the following - Bus-Mastering SCSI-2 Host Adapters for the ISA, EISA, VL, and PCI - buses. This Linux driver supports all of these adapters. + RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow + (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI + buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit + transfer) SCSI Host Adapters for the PCI bus. The CDB counts below indicate the number of SCSI CDB (Command Descriptor Block) requests that can be stored in the RISC chip @@ -72,7 +73,7 @@ ABP930U - Bus-Master PCI Ultra (16 CDB) ABP930UA - Bus-Master PCI Ultra (16 CDB) ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2) - ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) + ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) (Footnote 2) Single Channel Products: ABP542 - Bus-Master ISA with floppy (240 CDB) @@ -82,11 +83,14 @@ ABP940U - Bus-Master PCI Ultra (240 CDB) ABP970 - Bus-Master PCI MAC/PC (240 CDB) ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB) + ABP940UW - Bus-Master PCI Ultra-Wide (240 CDB) - Dual Channel Products: + Multi Channel Products: ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel) + ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel) + ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel) Footnotes: 1. This board has been shipped by HP with the 4020i CD-R drive. @@ -264,6 +268,7 @@ --- Driver Options --- Debugging Header --- Asc Library Constants and Macros + --- Adv Library Constants and Macros --- Driver Constants and Macros --- Driver Structures --- Driver Data @@ -272,20 +277,24 @@ --- Loadable Driver Support --- Miscellaneous Driver Functions --- Functions Required by the Asc Library + --- Functions Required by the Adv Library --- Tracing and Debugging Functions --- Asc Library Functions + --- Adv Library Functions 3. The string 'XXX' is used to flag code that needs to be re-written or that contains a problem that needs to be addressed. 4. I have stripped comments from and reformatted the source for the - Asc Library which is included in this file. I haven't done this - to obfuscate the code. Actually I have done this to deobfuscate - the code. The Asc Library source can be found under the following - headings. + Asc Library and Adv Library to reduce the size of this file. This + source can be found under the following headings. The Asc Library + is used to support Narrow Boards. The Adv Library is used to + support Wide Boards. --- Asc Library Constants and Macros + --- Adv Library Constants and Macros --- Asc Library Functions + --- Adv Library Functions G. Driver Compile Time Options and Debugging @@ -308,7 +317,7 @@ Enabling this option adds tracing functions to the driver and the ability to set a driver tracing level at boot time. This - option will also symbols not required outside the driver to + option will also export symbols not required outside the driver to the kernel name space. This option is very useful for debugging the driver, but it will add to the size of the driver execution image and add overhead to the execution of the driver. @@ -319,7 +328,7 @@ If the driver is loaded at boot time and the LILO Driver Option is included in the system, the debug level can be changed by - specifying a 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. The + specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The first three hex digits of the pseudo I/O Port must be set to 'deb' and the fourth hex digit specifies the debug level: 0 - F. The following command line will look for an adapter at 0x330 @@ -350,11 +359,6 @@ I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c prevents most level 1 debug messages from being lost. - this constant for debugging purposes, but for normal use of - the driver the constant should not be defined. This option - does not add overhead to the driver, but it does add unnecessary - symbols to the kernel name space. - 3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0) Enabling this option adds statistics collection and display @@ -379,7 +383,6 @@ When ADVANSYS_STATS is not defined the AdvanSys /proc files only contain adapter and device configuration information. - H. Driver LILO Option If init/main.c is modified as described in the 'Directions for Adding @@ -406,7 +409,7 @@ insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330 - If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_BOARD_SUPPORTED + 1) + If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port may be added to specify the driver debug level. Refer to the 'Driver Compile Time Options and Debugging' section above for more information. @@ -505,7 +508,7 @@ repeat busy or QUEUE FULL status returned by a device. 2. Incorporate miscellaneous Asc Library bug fixes. 3. To allow the driver to work in kernels with broken module - support set 'cmd_per_lun' if the driver is compile as a + support set 'cmd_per_lun' if the driver is compiled as a module. This change affects kernels v1.3.89 to present. 4. Remove PCI BIOS address from the driver banner. The PCI BIOS is relocated by the motherboard BIOS and its new address can @@ -541,13 +544,42 @@ option is enabled by default. 2.8 (5/26/97): - 1. Change version number to 2.8, skipping 2.3 through 2.7, in - order to synchronize the Linux driver version numbering with - other AdvanSys drivers. - 2. Reformat source files without tabs to give everyone everyone - the same view of the file regardless of the tab setting used. + 1. Change version number to 2.8 to synchronize the Linux driver + version numbering with other AdvanSys drivers. + 2. Reformat source files without tabs to present the same view + of the file to everyone regardless of the editor tab setting + being used. 3. Add Asc Library bug fixes. + 3.1A (1/8/98): + 1. Change version number to 3.1 to indicate that support for + Ultra-Wide adapters (ABP-940UW) is included in this release. + 2. Add Asc Library (Narrow Board) bug fixes. + 3. Report an underrun condition with the host status byte set + to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which + causes the underrun condition to be ignored. When Linux defines + its own DID_UNDERRUN the constant defined in this file can be + removed. + 4. Add patch to AscWaitTixISRDone(). + 5. Add support for up to 16 different AdvanSys host adapter SCSI + channels in one system. This allows four cards with four channels + to be used in one system. + + 3.1B (1/9/98): + 1. Handle that PCI register base addresses are not always page + aligned even though ioremap() requires that the address argument + be page aligned. + + 3.1C (1/10/98): + 1. Update latest BIOS version to 3.1E. + 2. Don't set microcode SDTR variable at initialization. Instead + wait until device capabilities have been detected from an Inquiry + command. + + 3.1D (1/21/98): + 1. Improve performance when the driver is compiled as module by + allowing up to 64 scatter-gather elements instead of 8. + J. Known Problems or Issues 1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around @@ -563,8 +595,15 @@ Thomas E Zerucha pointed out a bug in advansys_biosparam() which was fixed in the 1.3 release. - Erik Ratcliffe has done a lot of testing of - the AdvanSys driver in the Caldera releases. + Erik Ratcliffe has done testing of the + AdvanSys driver in the Caldera releases. + + Rik van Riel provided a patch to + AscWaitTixISRDone() which he found necessary to make the + driver work with a SCSI-1 disk. + + Mark Moran has helped test Ultra-Wide + support in the 3.1A driver. L. AdvanSys Contact Information @@ -576,7 +615,7 @@ Tech Support: 1-800-525-7440/1-408-467-2930 BBS: 1-408-383-9540 (14400,N,8,1) Interactive FAX: 1-408-383-9753 - Customer Direct Sales: 1-800-883-1099/1-408-383-5777 + Customer Direct Sales: 1-800-525-7443/1-408-383-5777 Tech Support E-Mail: support@advansys.com FTP Site: ftp.advansys.com (login: anonymous) Web Site: http://www.advansys.com @@ -613,6 +652,7 @@ #include #include #include +#include #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) #include #endif /* version >= v1.3.0 */ @@ -633,6 +673,15 @@ #include "sd.h" #include "advansys.h" +#include + +/* + * If Linux eventually defines a DID_UNDERRUN, the constant here can be + * removed. The current value of zero for DID_UNDERRUN results in underrun + * conditions being ignored. + */ +#define DID_UNDERRUN 0 + /* * --- Driver Options @@ -646,7 +695,7 @@ /* * Because of no /proc to display them, statistics are disabled - * for version prior to v1.3.0. + * for versions prior to v1.3.0. */ #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) #undef ADVANSYS_STATS /* Disable statistics */ @@ -672,7 +721,7 @@ #define ASC_LIB_VERSION_MAJOR 1 #define ASC_LIB_VERSION_MINOR 22 -#define ASC_LIB_SERIAL_NUMBER 105 +#define ASC_LIB_SERIAL_NUMBER 111 typedef unsigned char uchar; @@ -769,27 +818,6 @@ #define ASC_MAX_SG_QUEUE 7 #define ASC_MAX_SG_LIST SG_ALL -#define CC_CLEAR_LRAM_SRB_PTR FALSE -#define CC_VERIFY_LRAM_COPY FALSE -#define CC_DEBUG_SG_LIST FALSE -#define CC_FAST_STRING_IO FALSE -#define CC_WRITE_IO_COUNT FALSE -#define CC_CLEAR_DMA_REMAIN FALSE -#define CC_DISABLE_PCI_PARITY_INT TRUE -#define CC_LITTLE_ENDIAN_HOST TRUE -#define CC_STRUCT_ALIGNED TRUE -#define CC_MEMORY_MAPPED_IO FALSE -#define CC_INCLUDE_EEP_CONFIG TRUE -#define CC_PCI_ULTRA TRUE -#define CC_ASC_SCSI_Q_USRDEF FALSE -#define CC_ASC_SCSI_REQ_Q_USRDEF FALSE -#define CC_ASCISR_CHECK_INT_PENDING TRUE -#define CC_CHK_FIX_EEP_CONTENT TRUE -#define CC_INCLUDE_EEP_CONFIG TRUE -#define CC_PLEXTOR_VL FALSE -#define CC_TMP_USE_EEP_SDTR FALSE -#define CC_CHK_COND_REDO_SDTR TRUE - #define ASC_CS_TYPE unsigned short #ifndef asc_ptr_type #define asc_ptr_type @@ -840,27 +868,6 @@ #define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL) #define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL) #define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL) -#if !CC_STRUCT_ALIGNED -#define DvcGetQinfo(iop_base, s_addr, outbuf, words) \ -AscMemWordCopyFromLram(iop_base, s_addr, outbuf, words) -#define DvcPutScsiQ(iop_base, s_addr, outbuf, words) \ -AscMemWordCopyToLram(iop_base, s_addr, outbuf, words) -#endif -#ifdef ASC_CHIP_VERSION -#endif -#if CC_MEMORY_MAPPED_IO -#define inp(port) *((uchar *)(port)) -#define outp(port, data) *((uchar *)(port)) = (uchar)(data) -#if CC_LITTLE_ENDIAN_HOST -#define inpw(port) *((ushort *)(port)) -#define outpw(port, data) *((ushort *)(port)) = (ushort)(data) -#else -#define inpw(port) EndianSwap16Bit((*((ushort *)(port)))) -#define outpw(port, data) *((ushort *)(port)) = EndianSwap16Bit((ushort)(data)) -#define inpw_noswap(port) *((ushort *)(port)) -#define outpw_noswap(port, data) *((ushort *)(port)) = (ushort)(data) -#endif -#endif #ifndef inpw_noswap #define inpw_noswap(port) inpw(port) #endif @@ -901,6 +908,7 @@ #define ASC_MAX_SENSE_LEN 32 #define ASC_MIN_SENSE_LEN 14 #define ASC_MAX_CDB_LEN 12 +#define ASC_SCSI_RESET_HOLD_TIME_US 60 #define SCSICMD_TestUnitReady 0x00 #define SCSICMD_Rewind 0x01 #define SCSICMD_Rezero 0x01 @@ -963,6 +971,7 @@ #define SCSI_SENKEY_VOL_OVERFLOW 0x0D #define SCSI_SENKEY_MISCOMP 0x0E #define SCSI_SENKEY_RESERVED 0x0F +#define SCSI_ASC_NOMEDIA 0x3A #define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4)) #define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F)) #define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13)) @@ -1005,48 +1014,22 @@ #define M2_QTAG_MSG_ORDERED 0x22 #define M2_IGNORE_WIDE_RESIDUE 0x23 -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar peri_dvc_type:5; uchar peri_qualifier:3; } ASC_SCSI_INQ0; -#else -typedef struct { - uchar peri_qualifier:3; - uchar peri_dvc_type:5; -} ASC_SCSI_INQ0; - -#endif -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar dvc_type_modifier:7; uchar rmb:1; } ASC_SCSI_INQ1; -#else -typedef struct { - uchar rmb:1; - uchar dvc_type_modifier:7; -} ASC_SCSI_INQ1; - -#endif -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar ansi_apr_ver:3; uchar ecma_ver:3; uchar iso_ver:2; } ASC_SCSI_INQ2; -#else -typedef struct { - uchar iso_ver:2; - uchar ecma_ver:3; - uchar ansi_apr_ver:3; -} ASC_SCSI_INQ2; - -#endif -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar rsp_data_fmt:4; uchar res:2; @@ -1054,16 +1037,6 @@ uchar aenc:1; } ASC_SCSI_INQ3; -#else -typedef struct { - uchar aenc:1; - uchar TemIOP:1; - uchar res:2; - uchar rsp_data_fmt:4; -} ASC_SCSI_INQ3; - -#endif -#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar StfRe:1; uchar CmdQue:1; @@ -1075,19 +1048,6 @@ uchar RelAdr:1; } ASC_SCSI_INQ7; -#else -typedef struct { - uchar RelAdr:1; - uchar WBus32:1; - uchar WBus16:1; - uchar Sync:1; - uchar Linked:1; - uchar Reserved:1; - uchar CmdQue:1; - uchar StfRe:1; -} ASC_SCSI_INQ7; - -#endif typedef struct { ASC_SCSI_INQ0 byte0; ASC_SCSI_INQ1 byte1; @@ -1102,7 +1062,6 @@ uchar product_rev_level[4]; } ASC_SCSI_INQUIRY; -#if CC_LITTLE_ENDIAN_HOST typedef struct asc_req_sense { uchar err_code:7; uchar info_valid:1; @@ -1126,31 +1085,6 @@ uchar info2[4]; } ASC_REQ_SENSE; -#else -typedef struct asc_req_sense { - uchar info_valid:1; - uchar err_code:7; - uchar segment_no; - uchar file_mark:1; - uchar sense_EOM:1; - uchar sense_ILI:1; - uchar reserved_bit:1; - uchar sense_key:4; - uchar info1[4]; - uchar add_sense_len; - uchar cmd_sp_info[4]; - uchar asc; - uchar ascq; - uchar fruc; - uchar sks_valid:1; - uchar sks_byte0:7; - uchar sks_bytes[2]; - uchar notused[2]; - uchar ex_sense_code; - uchar info2[4]; -} ASC_REQ_SENSE; - -#endif #define ASC_SG_LIST_PER_Q 7 #define QS_FREE 0x00 #define QS_READY 0x01 @@ -1348,9 +1282,6 @@ ASC_SCSIQ_2 q2; uchar *cdbptr; ASC_SG_HEAD *sg_head; -#if CC_ASC_SCSI_Q_USRDEF - ASC_SCSI_Q_USR usr; -#endif } ASC_SCSI_Q; typedef struct asc_scsi_req_q { @@ -1362,9 +1293,6 @@ ASC_SCSIQ_3 r3; uchar cdb[ASC_MAX_CDB_LEN]; uchar sense[ASC_MIN_SENSE_LEN]; -#if CC_ASC_SCSI_REQ_Q_USRDEF - ASC_SCSI_REQ_Q_USR usr; -#endif } ASC_SCSI_REQ_Q; typedef struct asc_scsi_bios_req_q { @@ -1569,9 +1497,10 @@ ushort mcode_date; ushort mcode_version; uchar max_tag_qng[ASC_MAX_TID + 1]; - uchar *overrun_buf; + uchar *overrun_buf; uchar sdtr_period_offset[ASC_MAX_TID + 1]; ushort pci_slot_info; + uchar adapter_info[6]; } ASC_DVC_CFG; #define ASC_DEF_DVC_CNTL 0xFFFF @@ -1856,7 +1785,7 @@ #define ASC_CFG0_SCSI_PARITY_ON 0x0800 #define ASC_CFG1_SCSI_TARGET_ON 0x0080 #define ASC_CFG1_LRAM_8BITS_ON 0x0800 -#define ASC_CFG_MSW_CLR_MASK 0x30C0 +#define ASC_CFG_MSW_CLR_MASK 0x3080 #define CSW_TEST1 (ASC_CS_TYPE)0x8000 #define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000 #define CSW_RESERVED1 (ASC_CS_TYPE)0x2000 @@ -2000,7 +1929,7 @@ STATIC void AscDisableInterrupt(PortAddr); STATIC void AscEnableInterrupt(PortAddr); STATIC void AscSetBank(PortAddr, uchar); -STATIC int AscResetChipAndScsiBus(PortAddr); +STATIC int AscResetChipAndScsiBus(ASC_DVC_VAR *); STATIC ushort AscGetIsaDmaChannel(PortAddr); STATIC ushort AscSetIsaDmaChannel(PortAddr, ushort); STATIC uchar AscSetIsaDmaSpeed(PortAddr, uchar); @@ -2143,10 +2072,1120 @@ /* + * --- Adv Library Constants and Macros + */ + +#define ADV_LIB_VERSION_MAJOR 3 +#define ADV_LIB_VERSION_MINOR 34 + +/* d_os_dep.h */ +#define ADV_OS_LINUX + +/* + * Define Adv Library required special types. + */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) +#define AdvPortAddr unsigned short /* I/O Port address size */ +#else /* version >= v1,3,0 */ +#define AdvPortAddr unsigned long /* Virtual memory address size */ +#endif /* version >= v1,3,0 */ + +/* + * Define Adv Library required memory access macros. + */ +#define ADV_MEM_READB(addr) readb(addr) +#define ADV_MEM_READW(addr) readw(addr) +#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr) +#define ADV_MEM_WRITEW(addr, word) writew(word, addr) + +/* + * The I/O memory mapping function names changed in 2.1.X. + */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0) +#define ioremap vremap +#define iounmap vfree +#endif /* version < v2.1.0 */ + +/* + * Define total number of simultaneous maximum element scatter-gather + * requests, i.e. ADV_TOT_SG_LIST * ADV_MAX_SG_LIST is the total number + * of simultaneous scatter-gather elements supported per wide adapter. + */ +#define ADV_TOT_SG_LIST 64 + +/* + * Define Adv Library required per request scatter-gather element limit. + */ +#define ADV_MAX_SG_LIST 64 + +/* + * Scatter-Gather Definitions per request. + * + * Because SG block memory is allocated in virtual memory but is + * referenced by the microcode as physical memory, we need to do + * calculations to insure there will be enough physically contiguous + * memory to support ADV_MAX_SG_LIST SG entries. + */ + +/* Number of SG blocks needed. */ +#define ADV_NUM_SG_BLOCK \ + ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK) + +/* Total contiguous memory needed for SG blocks. */ +#define ADV_SG_TOTAL_MEM_SIZE \ + (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK) + +#define ASC_PAGE_SIZE PAGE_SIZE + +/* + * Number of page crossings possible for the total contiguous virtual memory + * needed for SG blocks. + * + * We need to allocate this many additional SG blocks in virtual memory to + * insure there will be space for ADV_NUM_SG_BLOCK physically contiguous + * scatter-gather blocks. + */ +#define ADV_NUM_PAGE_CROSSING \ + ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE) + +/* + * Define Adv Library Assertion Macro. + */ + +#define ADV_ASSERT(a) ASC_ASSERT(a) + +/* a_condor.h */ +#define ADV_PCI_VENDOR_ID 0x10CD +#define ADV_PCI_DEVICE_ID_REV_A 0x2300 + +#define ASC_EEP_DVC_CFG_BEGIN (0x00) +#define ASC_EEP_DVC_CFG_END (0x15) +#define ASC_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */ +#define ASC_EEP_MAX_WORD_ADDR (0x1E) + +#define ASC_EEP_DELAY_MS 100 + +/* + * EEPROM bits reference by the RISC after initialization. + */ +#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */ +#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */ +#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */ + +/* + * EEPROM configuration format + * + * Field naming convention: + * + * *_enable indicates the field enables or disables the feature. The + * value is never reset. + * + * *_able indicates both whether a feature should be enabled or disabled + * and whether a device isi capable of the feature. At initialization + * this field may be set, but later if a device is found to be incapable + * of the feature, the field is cleared. + * + * Default values are maintained in a_init.c in the structure + * Default_EEPROM_Config. + */ +typedef struct adveep_config +{ + /* Word Offset, Description */ + + ushort cfg_lsw; /* 00 power up initialization */ + /* bit 13 set - Term Polarity Control */ + /* bit 14 set - BIOS Enable */ + /* bit 15 set - Big Endian Mode */ + ushort cfg_msw; /* 01 unused */ + ushort disc_enable; /* 02 disconnect enable */ + ushort wdtr_able; /* 03 Wide DTR able */ + ushort sdtr_able; /* 04 Synchronous DTR able */ + ushort start_motor; /* 05 send start up motor */ + ushort tagqng_able; /* 06 tag queuing able */ + ushort bios_scan; /* 07 BIOS device control */ + ushort scam_tolerant; /* 08 no scam */ + + uchar adapter_scsi_id; /* 09 Host Adapter ID */ + uchar bios_boot_delay; /* power up wait */ + + uchar scsi_reset_delay; /* 10 reset delay */ + uchar bios_id_lun; /* first boot device scsi id & lun */ + /* high nibble is lun */ + /* low nibble is scsi id */ + + uchar termination; /* 11 0 - automatic */ + /* 1 - low off / high off */ + /* 2 - low off / high on */ + /* 3 - low on / high on */ + /* There is no low on / high off */ + + uchar reserved1; /* reserved byte (not used) */ + + ushort bios_ctrl; /* 12 BIOS control bits */ + /* bit 0 set: BIOS don't act as initiator. */ + /* bit 1 set: BIOS > 1 GB support */ + /* bit 2 set: BIOS > 2 Disk Support */ + /* bit 3 set: BIOS don't support removables */ + /* bit 4 set: BIOS support bootable CD */ + /* bit 5 set: */ + /* bit 6 set: BIOS support multiple LUNs */ + /* bit 7 set: BIOS display of message */ + /* bit 8 set: */ + /* bit 9 set: Reset SCSI bus during init. */ + /* bit 10 set: */ + /* bit 11 set: No verbose initialization. */ + /* bit 12 set: SCSI parity enabled */ + /* bit 13 set: */ + /* bit 14 set: */ + /* bit 15 set: */ + ushort ultra_able; /* 13 ULTRA speed able */ + ushort reserved2; /* 14 reserved */ + uchar max_host_qng; /* 15 maximum host queuing */ + uchar max_dvc_qng; /* maximum per device queuing */ + ushort dvc_cntl; /* 16 control bit for driver */ + ushort bug_fix; /* 17 control bit for bug fix */ + ushort serial_number_word1; /* 18 Board serial number word 1 */ + ushort serial_number_word2; /* 19 Board serial number word 2 */ + ushort serial_number_word3; /* 20 Board serial number word 3 */ + ushort check_sum; /* 21 EEP check sum */ + uchar oem_name[16]; /* 22 OEM name */ + ushort dvc_err_code; /* 30 last device driver error code */ + ushort adv_err_code; /* 31 last uc and Adv Lib error code */ + ushort adv_err_addr; /* 32 last uc error address */ + ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ + ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ + ushort saved_adv_err_addr; /* 35 saved last uc error address */ + ushort num_of_err; /* 36 number of error */ +} ADVEEP_CONFIG; + +/* + * EEPROM Commands + */ +#define ASC_EEP_CMD_DONE 0x0200 +#define ASC_EEP_CMD_DONE_ERR 0x0001 + +/* cfg_word */ +#define EEP_CFG_WORD_BIG_ENDIAN 0x8000 + +/* bios_ctrl */ +#define BIOS_CTRL_BIOS 0x0001 +#define BIOS_CTRL_EXTENDED_XLAT 0x0002 +#define BIOS_CTRL_GT_2_DISK 0x0004 +#define BIOS_CTRL_BIOS_REMOVABLE 0x0008 +#define BIOS_CTRL_BOOTABLE_CD 0x0010 +#define BIOS_CTRL_MULTIPLE_LUN 0x0040 +#define BIOS_CTRL_DISPLAY_MSG 0x0080 +#define BIOS_CTRL_NO_SCAM 0x0100 +#define BIOS_CTRL_RESET_SCSI_BUS 0x0200 +#define BIOS_CTRL_INIT_VERBOSE 0x0800 +#define BIOS_CTRL_SCSI_PARITY 0x1000 + +/* + * ASC 3550 Internal Memory Size - 8KB + */ +#define ADV_CONDOR_MEMSIZE 0x2000 /* 8 KB Internal Memory */ + +/* + * ASC 3550 I/O Length - 64 bytes + */ +#define ADV_CONDOR_IOLEN 0x40 /* I/O Port Range in bytes */ + +/* + * Byte I/O register address from base of 'iop_base'. + */ +#define IOPB_INTR_STATUS_REG 0x00 +#define IOPB_CHIP_ID_1 0x01 +#define IOPB_INTR_ENABLES 0x02 +#define IOPB_CHIP_TYPE_REV 0x03 +#define IOPB_RES_ADDR_4 0x04 +#define IOPB_RES_ADDR_5 0x05 +#define IOPB_RAM_DATA 0x06 +#define IOPB_RES_ADDR_7 0x07 +#define IOPB_FLAG_REG 0x08 +#define IOPB_RES_ADDR_9 0x09 +#define IOPB_RISC_CSR 0x0A +#define IOPB_RES_ADDR_B 0x0B +#define IOPB_RES_ADDR_C 0x0C +#define IOPB_RES_ADDR_D 0x0D +#define IOPB_RES_ADDR_E 0x0E +#define IOPB_RES_ADDR_F 0x0F +#define IOPB_MEM_CFG 0x10 +#define IOPB_RES_ADDR_11 0x11 +#define IOPB_RES_ADDR_12 0x12 +#define IOPB_RES_ADDR_13 0x13 +#define IOPB_FLASH_PAGE 0x14 +#define IOPB_RES_ADDR_15 0x15 +#define IOPB_RES_ADDR_16 0x16 +#define IOPB_RES_ADDR_17 0x17 +#define IOPB_FLASH_DATA 0x18 +#define IOPB_RES_ADDR_19 0x19 +#define IOPB_RES_ADDR_1A 0x1A +#define IOPB_RES_ADDR_1B 0x1B +#define IOPB_RES_ADDR_1C 0x1C +#define IOPB_RES_ADDR_1D 0x1D +#define IOPB_RES_ADDR_1E 0x1E +#define IOPB_RES_ADDR_1F 0x1F +#define IOPB_DMA_CFG0 0x20 +#define IOPB_DMA_CFG1 0x21 +#define IOPB_TICKLE 0x22 +#define IOPB_DMA_REG_WR 0x23 +#define IOPB_SDMA_STATUS 0x24 +#define IOPB_SCSI_BYTE_CNT 0x25 +#define IOPB_HOST_BYTE_CNT 0x26 +#define IOPB_BYTE_LEFT_TO_XFER 0x27 +#define IOPB_BYTE_TO_XFER_0 0x28 +#define IOPB_BYTE_TO_XFER_1 0x29 +#define IOPB_BYTE_TO_XFER_2 0x2A +#define IOPB_BYTE_TO_XFER_3 0x2B +#define IOPB_ACC_GRP 0x2C +#define IOPB_RES_ADDR_2D 0x2D +#define IOPB_DEV_ID 0x2E +#define IOPB_RES_ADDR_2F 0x2F +#define IOPB_SCSI_DATA 0x30 +#define IOPB_RES_ADDR_31 0x31 +#define IOPB_RES_ADDR_32 0x32 +#define IOPB_SCSI_DATA_HSHK 0x33 +#define IOPB_SCSI_CTRL 0x34 +#define IOPB_RES_ADDR_35 0x35 +#define IOPB_RES_ADDR_36 0x36 +#define IOPB_RES_ADDR_37 0x37 +#define IOPB_RES_ADDR_38 0x38 +#define IOPB_RES_ADDR_39 0x39 +#define IOPB_RES_ADDR_3A 0x3A +#define IOPB_RES_ADDR_3B 0x3B +#define IOPB_RFIFO_CNT 0x3C +#define IOPB_RES_ADDR_3D 0x3D +#define IOPB_RES_ADDR_3E 0x3E +#define IOPB_RES_ADDR_3F 0x3F + +/* + * Word I/O register address from base of 'iop_base'. + */ +#define IOPW_CHIP_ID_0 0x00 /* CID0 */ +#define IOPW_CTRL_REG 0x02 /* CC */ +#define IOPW_RAM_ADDR 0x04 /* LA */ +#define IOPW_RAM_DATA 0x06 /* LD */ +#define IOPW_RES_ADDR_08 0x08 +#define IOPW_RISC_CSR 0x0A /* CSR */ +#define IOPW_SCSI_CFG0 0x0C /* CFG0 */ +#define IOPW_SCSI_CFG1 0x0E /* CFG1 */ +#define IOPW_RES_ADDR_10 0x10 +#define IOPW_SEL_MASK 0x12 /* SM */ +#define IOPW_RES_ADDR_14 0x14 +#define IOPW_FLASH_ADDR 0x16 /* FA */ +#define IOPW_RES_ADDR_18 0x18 +#define IOPW_EE_CMD 0x1A /* EC */ +#define IOPW_EE_DATA 0x1C /* ED */ +#define IOPW_SFIFO_CNT 0x1E /* SFC */ +#define IOPW_RES_ADDR_20 0x20 +#define IOPW_Q_BASE 0x22 /* QB */ +#define IOPW_QP 0x24 /* QP */ +#define IOPW_IX 0x26 /* IX */ +#define IOPW_SP 0x28 /* SP */ +#define IOPW_PC 0x2A /* PC */ +#define IOPW_RES_ADDR_2C 0x2C +#define IOPW_RES_ADDR_2E 0x2E +#define IOPW_SCSI_DATA 0x30 /* SD */ +#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */ +#define IOPW_SCSI_CTRL 0x34 /* SC */ +#define IOPW_HSHK_CFG 0x36 /* HCFG */ +#define IOPW_SXFR_STATUS 0x36 /* SXS */ +#define IOPW_SXFR_CNTL 0x38 /* SXL */ +#define IOPW_SXFR_CNTH 0x3A /* SXH */ +#define IOPW_RES_ADDR_3C 0x3C +#define IOPW_RFIFO_DATA 0x3E /* RFD */ + +/* + * Doubleword I/O register address from base of 'iop_base'. + */ +#define IOPDW_RES_ADDR_0 0x00 +#define IOPDW_RAM_DATA 0x04 +#define IOPDW_RES_ADDR_8 0x08 +#define IOPDW_RES_ADDR_C 0x0C +#define IOPDW_RES_ADDR_10 0x10 +#define IOPDW_RES_ADDR_14 0x14 +#define IOPDW_RES_ADDR_18 0x18 +#define IOPDW_RES_ADDR_1C 0x1C +#define IOPDW_SDMA_ADDR0 0x20 +#define IOPDW_SDMA_ADDR1 0x24 +#define IOPDW_SDMA_COUNT 0x28 +#define IOPDW_SDMA_ERROR 0x2C +#define IOPDW_RDMA_ADDR0 0x30 +#define IOPDW_RDMA_ADDR1 0x34 +#define IOPDW_RDMA_COUNT 0x38 +#define IOPDW_RDMA_ERROR 0x3C + +#define ADV_CHIP_ID_BYTE 0x25 +#define ADV_CHIP_ID_WORD 0x04C1 + +#define ADV_SC_SCSI_BUS_RESET 0x2000 + +#define ADV_INTR_ENABLE_HOST_INTR 0x01 +#define ADV_INTR_ENABLE_SEL_INTR 0x02 +#define ADV_INTR_ENABLE_DPR_INTR 0x04 +#define ADV_INTR_ENABLE_RTA_INTR 0x08 +#define ADV_INTR_ENABLE_RMA_INTR 0x10 +#define ADV_INTR_ENABLE_RST_INTR 0x20 +#define ADV_INTR_ENABLE_DPE_INTR 0x40 +#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80 + +#define ADV_INTR_STATUS_INTRA 0x01 +#define ADV_INTR_STATUS_INTRB 0x02 +#define ADV_INTR_STATUS_INTRC 0x04 + +#define ADV_RISC_CSR_STOP (0x0000) +#define ADV_RISC_TEST_COND (0x2000) +#define ADV_RISC_CSR_RUN (0x4000) +#define ADV_RISC_CSR_SINGLE_STEP (0x8000) + +#define ADV_CTRL_REG_HOST_INTR 0x0100 +#define ADV_CTRL_REG_SEL_INTR 0x0200 +#define ADV_CTRL_REG_DPR_INTR 0x0400 +#define ADV_CTRL_REG_RTA_INTR 0x0800 +#define ADV_CTRL_REG_RMA_INTR 0x1000 +#define ADV_CTRL_REG_RES_BIT14 0x2000 +#define ADV_CTRL_REG_DPE_INTR 0x4000 +#define ADV_CTRL_REG_POWER_DONE 0x8000 +#define ADV_CTRL_REG_ANY_INTR 0xFF00 + +#define ADV_CTRL_REG_CMD_RESET 0x00C6 +#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5 +#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4 +#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3 +#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2 + +#define ADV_SCSI_CTRL_RSTOUT 0x2000 + +#define AdvIsIntPending(port) \ + (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR) + +/* + * SCSI_CFG0 Register bit definitions + */ +#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */ +#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */ +#define EVEN_PARITY 0x1000 /* Select Even Parity */ +#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */ +#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */ +#define PRIM_MODE 0x0100 /* Primitive SCSI mode */ +#define SCAM_EN 0x0080 /* Enable SCAM selection */ +#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */ +#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */ +#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */ +#define OUR_ID 0x000F /* SCSI ID */ + +/* + * SCSI_CFG1 Register bit definitions + */ +#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */ +#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */ +#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */ +#define FILTER_SEL 0x0C00 /* Filter Period Selection */ +#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */ +#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */ +#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */ +#define ACTIVE_DBL 0x0200 /* Disable Active Negation */ +#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */ +#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */ +#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */ +#define TERM_CTL 0x0030 /* External SCSI Termination Bits */ +#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */ +#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */ +#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */ + +#define CABLE_ILLEGAL_A 0x7 + /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */ + +#define CABLE_ILLEGAL_B 0xB + /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */ + +/* + The following table details the SCSI_CFG1 Termination Polarity, + Termination Control and Cable Detect bits. + + Cable Detect | Termination + Bit 3 2 1 0 | 5 4 | Notes + _____________|________|____________________ + 1 1 1 0 | on on | Internal wide only + 1 1 0 1 | on on | Internal narrow only + 1 0 1 1 | on on | External narrow only + 0 x 1 1 | on on | External wide only + 1 1 0 0 | on off| Internal wide and internal narrow + 1 0 1 0 | on off| Internal wide and external narrow + 0 x 1 0 | off off| Internal wide and external wide + 1 0 0 1 | on off| Internal narrow and external narrow + 0 x 0 1 | on off| Internal narrow and external wide + 1 1 1 1 | on on | No devices are attached + x 0 0 0 | on on | Illegal (all 3 connectors are used) + 0 x 0 0 | on on | Illegal (all 3 connectors are used) + + x means don't-care (either '0' or '1') + + If term_pol (bit 13) is '0' (active-low terminator enable), then: + 'on' is '0' and 'off' is '1'. + + If term_pol bit is '1' (meaning active-hi terminator enable), then: + 'on' is '1' and 'off' is '0'. + */ + +/* + * MEM_CFG Register bit definitions + */ +#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */ +#define FAST_EE_CLK 0x20 /* Diagnostic Bit */ +#define RAM_SZ 0x1C /* Specify size of RAM to RISC */ +#define RAM_SZ_2KB 0x00 /* 2 KB */ +#define RAM_SZ_4KB 0x04 /* 4 KB */ +#define RAM_SZ_8KB 0x08 /* 8 KB */ +#define RAM_SZ_16KB 0x0C /* 16 KB */ +#define RAM_SZ_32KB 0x10 /* 32 KB */ +#define RAM_SZ_64KB 0x14 /* 64 KB */ + +/* + * DMA_CFG0 Register bit definitions + * + * This register is only accessible to the host. + */ +#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */ +#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */ +#define FIFO_THRESH_16B 0x00 /* 16 bytes */ +#define FIFO_THRESH_32B 0x20 /* 32 bytes */ +#define FIFO_THRESH_48B 0x30 /* 48 bytes */ +#define FIFO_THRESH_64B 0x40 /* 64 bytes */ +#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */ +#define FIFO_THRESH_96B 0x60 /* 96 bytes */ +#define FIFO_THRESH_112B 0x70 /* 112 bytes */ +#define START_CTL 0x0C /* DMA start conditions */ +#define START_CTL_TH 0x00 /* Wait threshold level (default) */ +#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */ +#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */ +#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */ +#define READ_CMD 0x03 /* Memory Read Method */ +#define READ_CMD_MR 0x00 /* Memory Read */ +#define READ_CMD_MRL 0x02 /* Memory Read Long */ +#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */ + +/* a_advlib.h */ + +/* + * Adv Library Status Definitions + */ +#define ADV_TRUE 1 +#define ADV_FALSE 0 +#define ADV_NOERROR 1 +#define ADV_SUCCESS 1 +#define ADV_BUSY 0 +#define ADV_ERROR (-1) + + +/* + * ASC_DVC_VAR 'warn_code' values + */ +#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */ +#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */ +#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */ +#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */ + +#define ADV_MAX_TID 15 /* max. target identifier */ +#define ADV_MAX_LUN 7 /* max. logical unit number */ + + +/* + * AscInitGetConfig() and AscInitAsc1000Driver() Definitions + * + * Error code values are set in ASC_DVC_VAR 'err_code'. + */ +#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */ +#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */ +#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */ +#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */ +#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */ +#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */ +#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */ +#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */ +#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */ +#define ASC_IERR_RW_LRAM 0x8000 /* read/write local RAM error */ + +/* + * Fixed locations of microcode operating variables. + */ +#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */ +#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */ +#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */ +#define ASC_MC_STACK_BEGIN 0x002E /* microcode stack begin */ +#define ASC_MC_STACK_END 0x0030 /* microcode stack end */ +#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */ +#define ASC_MC_VERSION_NUM 0x003A /* microcode number */ +#define ASCV_VER_SERIAL_W 0x003C /* used in dos_init */ +#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */ +#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */ +#define ASC_MC_HALTCODE 0x0094 /* microcode halt code */ +#define ASC_MC_CALLERPC 0x0096 /* microcode halt caller PC */ +#define ASC_MC_ADAPTER_SCSI_ID 0x0098 /* one ID byte + reserved */ +#define ASC_MC_ULTRA_ABLE 0x009C +#define ASC_MC_SDTR_ABLE 0x009E +#define ASC_MC_TAGQNG_ABLE 0x00A0 +#define ASC_MC_DISC_ENABLE 0x00A2 +#define ASC_MC_IDLE_CMD 0x00A6 +#define ASC_MC_IDLE_PARA_STAT 0x00A8 +#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC +#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE +#define ASC_MC_DEFAULT_MEM_CFG 0x00B0 +#define ASC_MC_DEFAULT_SEL_MASK 0x00B2 +#define ASC_MC_RISC_NEXT_READY 0x00B4 +#define ASC_MC_RISC_NEXT_DONE 0x00B5 +#define ASC_MC_SDTR_DONE 0x00B6 +#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0 +#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0 +#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100 +#define ASC_MC_WDTR_ABLE 0x0120 /* Wide Transfer TID bitmask. */ +#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */ +#define ASC_MC_WDTR_DONE 0x0124 +#define ASC_MC_HOST_NEXT_READY 0x0128 /* Host Next Ready RQL Entry. */ +#define ASC_MC_HOST_NEXT_DONE 0x0129 /* Host Next Done RQL Entry. */ + +/* + * BIOS LRAM variable absolute offsets. + */ +#define BIOS_CODESEG 0x54 +#define BIOS_CODELEN 0x56 +#define BIOS_SIGNATURE 0x58 +#define BIOS_VERSION 0x5A +#define BIOS_SIGNATURE 0x58 + +/* + * Microcode Control Flags + * + * Flags set by the Adv Library in RISC variable 'control_flag' (0x122) + * and handled by the microcode. + */ +#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */ + +/* + * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format + */ +#define HSHK_CFG_WIDE_XFR 0x8000 +#define HSHK_CFG_RATE 0x0F00 +#define HSHK_CFG_OFFSET 0x001F + +/* + * LRAM RISC Queue Lists (LRAM addresses 0x1200 - 0x19FF) + * + * Each of the 255 Adv Library/Microcode RISC queue lists or mailboxes + * starting at LRAM address 0x1200 is 8 bytes and has the following + * structure. Only 253 of these are actually used for command queues. + */ + +#define ASC_MC_RISC_Q_LIST_BASE 0x1200 +#define ASC_MC_RISC_Q_LIST_SIZE 0x0008 +#define ASC_MC_RISC_Q_TOTAL_CNT 0x00FF /* Num. queue slots in LRAM. */ +#define ASC_MC_RISC_Q_FIRST 0x0001 +#define ASC_MC_RISC_Q_LAST 0x00FF + +#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */ +#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */ +#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */ +#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */ + +/* RISC Queue List structure - 8 bytes */ +#define RQL_FWD 0 /* forward pointer (1 byte) */ +#define RQL_BWD 1 /* backward pointer (1 byte) */ +#define RQL_STATE 2 /* state byte - free, ready, done, aborted (1 byte) */ +#define RQL_TID 3 /* request target id (1 byte) */ +#define RQL_PHYADDR 4 /* request physical pointer (4 bytes) */ + +/* RISC Queue List state values */ +#define ASC_MC_QS_FREE 0x00 +#define ASC_MC_QS_READY 0x01 +#define ASC_MC_QS_DONE 0x40 +#define ASC_MC_QS_ABORTED 0x80 + +/* RISC Queue List pointer values */ +#define ASC_MC_NULL_Q 0x00 /* NULL_Q == 0 */ +#define ASC_MC_BIOS_Q 0xFF /* BIOS_Q = 255 */ + +/* ASC_SCSI_REQ_Q 'cntl' field values */ +#define ASC_MC_QC_START_MOTOR 0x02 /* Issue start motor. */ +#define ASC_MC_QC_NO_OVERRUN 0x04 /* Don't report overrun. */ +#define ASC_MC_QC_FIRST_DMA 0x08 /* Internal microcode flag. */ +#define ASC_MC_QC_ABORTED 0x10 /* Request aborted by host. */ +#define ASC_MC_QC_REQ_SENSE 0x20 /* Auto-Request Sense. */ +#define ASC_MC_QC_DOS_REQ 0x80 /* Request issued by DOS. */ + + +/* + * ASC_SCSI_REQ_Q 'a_flag' definitions + * + * The Adv Library should limit use to the lower nibble (4 bits) of + * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag. + */ +#define ADV_POLL_REQUEST 0x01 /* poll for request completion */ +#define ADV_SCSIQ_DONE 0x02 /* request done */ + +/* + * Adapter temporary configuration structure + * + * This structure can be discarded after initialization. Don't add + * fields here needed after initialization. + * + * Field naming convention: + * + * *_enable indicates the field enables or disables a feature. The + * value of the field is never reset. + */ +typedef struct adv_dvc_cfg { + ushort disc_enable; /* enable disconnection */ + uchar chip_version; /* chip version */ + uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */ + ushort pci_device_id; /* PCI device code number */ + ushort lib_version; /* Adv Library version number */ + ushort control_flag; /* Microcode Control Flag */ + ushort mcode_date; /* Microcode date */ + ushort mcode_version; /* Microcode version */ + ushort pci_slot_info; /* high byte device/function number */ + /* bits 7-3 device num., bits 2-0 function num. */ + /* low byte bus num. */ + ushort bios_boot_wait; /* BIOS boot time delay */ + ushort serial1; /* EEPROM serial number word 1 */ + ushort serial2; /* EEPROM serial number word 2 */ + ushort serial3; /* EEPROM serial number word 3 */ +} ADV_DVC_CFG; + +/* + * Adapter operation variable structure. + * + * One structure is required per host adapter. + * + * Field naming convention: + * + * *_able indicates both whether a feature should be enabled or disabled + * and whether a device isi capable of the feature. At initialization + * this field may be set, but later if a device is found to be incapable + * of the feature, the field is cleared. + */ +typedef struct adv_dvc_var { + AdvPortAddr iop_base; /* I/O port address */ + ushort err_code; /* fatal error code */ + ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */ + Ptr2Func isr_callback; /* pointer to function, called in AdvISR() */ + Ptr2Func sbreset_callback; /* pointer to function, called in AdvISR() */ + ushort wdtr_able; /* try WDTR for a device */ + ushort sdtr_able; /* try SDTR for a device */ + ushort ultra_able; /* try SDTR Ultra speed for a device */ + ushort tagqng_able; /* try tagged queuing with a device */ + uchar max_dvc_qng; /* maximum number of tagged commands per device */ + ushort start_motor; /* start motor command allowed */ + uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */ + uchar chip_no; /* should be assigned by caller */ + uchar max_host_qng; /* maximum number of Q'ed command allowed */ + uchar cur_host_qng; /* total number of queue command */ + uchar irq_no; /* IRQ number */ + ushort no_scam; /* scam_tolerant of EEPROM */ + ushort idle_cmd_done; /* microcode idle command done set by AdvISR() */ + ulong drv_ptr; /* driver pointer to private structure */ + uchar chip_scsi_id; /* chip SCSI target ID */ + /* + * Note: The following fields will not be used after initialization. The + * driver may discard the buffer after initialization is done. + */ + ADV_DVC_CFG *cfg; /* temporary configuration structure */ +} ADV_DVC_VAR; + +#define NO_OF_SG_PER_BLOCK 15 + +typedef struct asc_sg_block { + uchar reserved1; + uchar reserved2; + uchar first_entry_no; /* starting entry number */ + uchar last_entry_no; /* last entry number */ + struct asc_sg_block *sg_ptr; /* links to the next sg block */ + struct { + ulong sg_addr; /* SG element address */ + ulong sg_count; /* SG element count */ + } sg_list[NO_OF_SG_PER_BLOCK]; +} ADV_SG_BLOCK; + +/* + * ASC_SCSI_REQ_Q - microcode request structure + * + * All fields in this structure up to byte 60 are used by the microcode. + * The microcode makes assumptions about the size and ordering of fields + * in this structure. Do not change the structure definition here without + * coordinating the change with the microcode. + */ +typedef struct adv_scsi_req_q { + uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */ + uchar sg_entry_cnt; /* SG element count. Zero for no SG. */ + uchar target_id; /* Device target identifier. */ + uchar target_lun; /* Device target logical unit number. */ + ulong data_addr; /* Data buffer physical address. */ + ulong data_cnt; /* Data count. Ucode sets to residual. */ + ulong sense_addr; /* Sense buffer physical address. */ + ulong srb_ptr; /* Driver request pointer. */ + uchar a_flag; /* Adv Library flag field. */ + uchar sense_len; /* Auto-sense length. Ucode sets to residual. */ + uchar cdb_len; /* SCSI CDB length. */ + uchar tag_code; /* SCSI-2 Tag Queue Code: 00, 20-22. */ + uchar done_status; /* Completion status. */ + uchar scsi_status; /* SCSI status byte. */ + uchar host_status; /* Ucode host status. */ + uchar ux_sg_ix; /* Ucode working SG variable. */ + uchar cdb[12]; /* SCSI command block. */ + ulong sg_real_addr; /* SG list physical address. */ + struct adv_scsi_req_q *free_scsiq_link; + ulong ux_wk_data_cnt; /* Saved data count at disconnection. */ + struct adv_scsi_req_q *scsiq_ptr; + ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */ + /* + * End of microcode structure - 60 bytes. The rest of the structure + * is used by the Adv Library and ignored by the microcode. + */ + ulong vsense_addr; /* Sense buffer virtual address. */ + ulong vdata_addr; /* Data buffer virtual address. */ + uchar orig_sense_len; /* Original length of sense buffer. */ +} ADV_SCSI_REQ_Q; /* BIOS - 70 bytes, DOS - 76 bytes, W95, WNT - 69 bytes */ + +/* + * Microcode idle loop commands + */ +#define IDLE_CMD_COMPLETED 0 +#define IDLE_CMD_STOP_CHIP 0x0001 +#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002 +#define IDLE_CMD_SEND_INT 0x0004 +#define IDLE_CMD_ABORT 0x0008 +#define IDLE_CMD_DEVICE_RESET 0x0010 +#define IDLE_CMD_SCSI_RESET 0x0020 + +/* + * AdvSendIdleCmd() flag definitions. + */ +#define ADV_NOWAIT 0x01 + +/* + * Wait loop time out values. + */ +#define SCSI_WAIT_10_SEC 10 /* 10 seconds */ +#define SCSI_MS_PER_SEC 1000 /* milliseconds per second */ + +/* + * Device drivers must define the following functions. + */ +STATIC int DvcEnterCritical(void); +STATIC void DvcLeaveCritical(int); +STATIC void DvcSleepMilliSecond(ulong); +STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort); +STATIC void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar); +STATIC ulong DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, + uchar *, long *, int); +STATIC void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort); + +/* + * Adv Library functions available to drivers. + */ +STATIC int AdvExeScsiQueue(ADV_DVC_VAR *, + ADV_SCSI_REQ_Q *); +STATIC int AdvISR(ADV_DVC_VAR *); +STATIC int AdvInitGetConfig(ADV_DVC_VAR *); +STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *); +STATIC int AdvResetSB(ADV_DVC_VAR *); + +/* + * Internal Adv Library functions. + */ +STATIC int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong, int); +STATIC void AdvResetChip(ADV_DVC_VAR *); +STATIC int AdvSendScsiCmd(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); +STATIC void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); +STATIC int AdvInitFromEEP(ADV_DVC_VAR *); +STATIC ushort AdvGetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *); +STATIC void AdvSetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *); +STATIC void AdvWaitEEPCmd(AdvPortAddr); +STATIC ushort AdvReadEEPWord(AdvPortAddr, int); +STATIC void AdvResetSCSIBus(ADV_DVC_VAR *); + +/* + * PCI Bus Definitions + */ +#define AscPCICmdRegBits_BusMastering 0x0007 +#define AscPCICmdRegBits_ParErrRespCtrl 0x0040 + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) + +/* Read byte from a register. */ +#define AdvReadByteRegister(iop_base, reg_off) \ + (inp((iop_base) + (reg_off))) + +/* Write byte to a register. */ +#define AdvWriteByteRegister(iop_base, reg_off, byte) \ + (outp((iop_base) + (reg_off), (byte))) + +/* Read word (2 bytes) from a register. */ +#define AdvReadWordRegister(iop_base, reg_off) \ + (inpw((iop_base) + (reg_off))) + +/* Write word (2 bytes) to a register. */ +#define AdvWriteWordRegister(iop_base, reg_off, word) \ + (outpw((iop_base) + (reg_off), (word))) + +/* Read byte from LRAM. */ +#define AdvReadByteLram(iop_base, addr, byte) \ +do { \ + outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \ + (byte) = inp((iop_base) + IOPB_RAM_DATA); \ +} while (0) + +/* Write byte to LRAM. */ +#define AdvWriteByteLram(iop_base, addr, byte) \ + (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ + outp((iop_base) + IOPB_RAM_DATA, (byte))) + +/* Read word (2 bytes) from LRAM. */ +#define AdvReadWordLram(iop_base, addr, word) \ +do { \ + outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \ + (word) = inpw((iop_base) + IOPW_RAM_DATA); \ +} while (0) + +/* Write word (2 bytes) to LRAM. */ +#define AdvWriteWordLram(iop_base, addr, word) \ + (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ + outpw((iop_base) + IOPW_RAM_DATA, (word))) + +/* Write double word (4 bytes) to LRAM */ +/* Because of unspecified C language ordering don't use auto-increment. */ +#define AdvWriteDWordLram(iop_base, addr, dword) \ + ((outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \ + outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword) & 0xFFFF))), \ + (outpw((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \ + outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword >> 16) & 0xFFFF)))) + +/* Read word (2 bytes) from LRAM assuming that the address is already set. */ +#define AdvReadWordAutoIncLram(iop_base) \ + (inpw((iop_base) + IOPW_RAM_DATA)) + +/* Write word (2 bytes) to LRAM assuming that the address is already set. */ +#define AdvWriteWordAutoIncLram(iop_base, word) \ + (outpw((iop_base) + IOPW_RAM_DATA, (word))) + +#else /* version >= v1,3,0 */ + +/* Read byte from a register. */ +#define AdvReadByteRegister(iop_base, reg_off) \ + (ADV_MEM_READB((iop_base) + (reg_off))) + +/* Write byte to a register. */ +#define AdvWriteByteRegister(iop_base, reg_off, byte) \ + (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte))) + +/* Read word (2 bytes) from a register. */ +#define AdvReadWordRegister(iop_base, reg_off) \ + (ADV_MEM_READW((iop_base) + (reg_off))) + +/* Write word (2 bytes) to a register. */ +#define AdvWriteWordRegister(iop_base, reg_off, word) \ + (ADV_MEM_WRITEW((iop_base) + (reg_off), (word))) + +/* Read byte from LRAM. */ +#define AdvReadByteLram(iop_base, addr, byte) \ +do { \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \ + (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \ +} while (0) + +/* Write byte to LRAM. */ +#define AdvWriteByteLram(iop_base, addr, byte) \ + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ + ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte))) + +/* Read word (2 bytes) from LRAM. */ +#define AdvReadWordLram(iop_base, addr, word) \ +do { \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \ + (word) = ADV_MEM_READW((iop_base) + IOPW_RAM_DATA); \ +} while (0) + +/* Write word (2 bytes) to LRAM. */ +#define AdvWriteWordLram(iop_base, addr, word) \ + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) + +/* Write double word (4 bytes) to LRAM */ +/* Because of unspecified C language ordering don't use auto-increment. */ +#define AdvWriteDWordLram(iop_base, addr, dword) \ + ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \ + (ushort) ((dword) & 0xFFFF))), \ + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \ + ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \ + (ushort) ((dword >> 16) & 0xFFFF)))) + +/* Read word (2 bytes) from LRAM assuming that the address is already set. */ +#define AdvReadWordAutoIncLram(iop_base) \ + (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)) + +/* Write word (2 bytes) to LRAM assuming that the address is already set. */ +#define AdvWriteWordAutoIncLram(iop_base, word) \ + (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) + +#endif /* version >= v1,3,0 */ + +/* + * Define macro to check for Condor signature. + * + * Evaluate to ADV_TRUE if a Condor chip is found the specified port + * address 'iop_base'. Otherwise evalue to ADV_FALSE. + */ +#define AdvFindSignature(iop_base) \ + (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \ + ADV_CHIP_ID_BYTE) && \ + (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \ + ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE) + +/* + * Define macro to Return the version number of the chip at 'iop_base'. + * + * The second parameter 'bus_type' is currently unused. + */ +#define AdvGetChipVersion(iop_base, bus_type) \ + AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV) + +/* + * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must + * match the ASC_SCSI_REQ_Q 'srb_ptr' field. + * + * If the request has not yet been sent to the device it will simply be + * aborted from RISC memory. If the request is disconnected it will be + * aborted on reselection by sending an Abort Message to the target ID. + * + * Return value: + * ADV_TRUE(1) - Queue was successfully aborted. + * ADV_FALSE(0) - Queue was not found on the active queue list. + */ +#define AdvAbortSRB(asc_dvc, srb_ptr) \ + AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \ + (ulong) (srb_ptr), 0) + +/* + * Send a Bus Device Reset Message to the specified target ID. + * + * All outstanding commands will be purged if sending the + * Bus Device Reset Message is successful. + * + * Return Value: + * ADV_TRUE(1) - All requests on the target are purged. + * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests + * are not purged. + */ +#define AdvResetDevice(asc_dvc, target_id) \ + AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \ + (ulong) (target_id), 0) + +/* + * SCSI Wide Type definition. + */ +#define ADV_SCSI_BIT_ID_TYPE ushort + +/* + * AdvInitScsiTarget() 'cntl_flag' options. + */ +#define ADV_SCAN_LUN 0x01 +#define ADV_CAPINFO_NOLUN 0x02 + +/* + * Convert target id to target id bit mask. + */ +#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID)) + +/* + * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values. + */ + +#define QD_NO_STATUS 0x00 /* Request not completed yet. */ +#define QD_NO_ERROR 0x01 +#define QD_ABORTED_BY_HOST 0x02 +#define QD_WITH_ERROR 0x04 + +#define QHSTA_NO_ERROR 0x00 +#define QHSTA_M_SEL_TIMEOUT 0x11 +#define QHSTA_M_DATA_OVER_RUN 0x12 +#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13 +#define QHSTA_M_QUEUE_ABORTED 0x15 +#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */ +#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */ +#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */ +#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */ +#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */ +#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */ +#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */ +/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */ +#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */ +#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */ +#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */ +#define QHSTA_M_WTM_TIMEOUT 0x41 +#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42 +#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43 +#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44 +#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */ + +typedef int (* ADV_ISR_CALLBACK) + (ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); + +typedef int (* ADV_SBRESET_CALLBACK) + (ADV_DVC_VAR *); + +/* + * Default EEPROM Configuration structure defined in a_init.c. + */ +extern ADVEEP_CONFIG Default_EEPROM_Config; + +/* + * DvcGetPhyAddr() flag arguments + */ +#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */ +#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */ +#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */ +#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */ +#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */ + +/* 'IS_SCSIQ_FLAG is now obsolete; Instead use ADV_IS_SCSIQ_FLAG. */ +#define IS_SCSIQ_FLAG ADV_IS_SCSIQ_FLAQ + + +/* Return the address that is aligned at the next doubleword >= to 'addr'. */ +#define ADV_DWALIGN(addr) (((ulong) (addr) + 0x3) & ~0x3) + +/* + * Total contiguous memory needed for driver SG blocks. + * + * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum + * number of scatter-gather elements the driver supports in a + * single request. + */ + +#ifndef ADV_MAX_SG_LIST +Forced Error: Driver must define ADV_MAX_SG_LIST. +#endif /* ADV_MAX_SG_LIST */ + +#define ADV_SG_LIST_MAX_BYTE_SIZE \ + (sizeof(ADV_SG_BLOCK) * \ + ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)) + +/* + * A driver may optionally define the assertion macro ADV_ASSERT() in + * its d_os_dep.h file. If the macro has not already been defined, + * then define the macro to a no-op. + */ +#ifndef ADV_ASSERT +#define ADV_ASSERT(a) +#endif /* ADV_ASSERT */ + + +/* * --- Driver Constants and Macros */ -#define ASC_NUM_BOARD_SUPPORTED 4 +#define ASC_NUM_BOARD_SUPPORTED 16 +#define ASC_NUM_IOPORT_PROBE 4 #define ASC_NUM_BUS 4 /* Reference Scsi_Host hostdata */ @@ -2155,22 +3194,27 @@ /* asc_board_t flags */ #define ASC_HOST_IN_RESET 0x01 #define ASC_HOST_IN_ABORT 0x02 +#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */ +#define ASC_SELECT_QUEUE_DEPTHS 0x08 + +#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0) +#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD) #define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */ /* - * If the Linux kernel version supports throwing away initialization code + * If the Linux kernel version supports freeing initialization code * and data after loading, define macros for this purpose. These macros * are not used when the driver is built as a module, cf. linux/init.h. */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,23) -#define ASC_INITFUNC(func) __initfunc(func) -#define ASC_INITDATA __initdata -#define ASC_INIT __init -#else /* version >= v2.1.23 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23) #define ASC_INITFUNC(func) func #define ASC_INITDATA #define ASC_INIT +#else /* version >= v2.1.23 */ +#define ASC_INITFUNC(func) __initfunc(func) +#define ASC_INITDATA __initdata +#define ASC_INIT __init #endif /* version >= v2.1.23 */ #define ASC_INFO_SIZE 128 /* advansys_info() line size */ @@ -2216,11 +3260,11 @@ * REQTIMESTAMP() - system time stamp value */ typedef Scsi_Cmnd REQ, *REQP; -#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble)) -#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble)) +#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble)) +#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble)) #define REQPTID(reqp) ((reqp)->target) -#define REQPTIME(reqp) ((reqp)->SCp.this_residual) -#define REQTIMESTAMP() (jiffies) +#define REQPTIME(reqp) ((reqp)->SCp.this_residual) +#define REQTIMESTAMP() (jiffies) #define REQTIMESTAT(function, ascq, reqp, tid) \ { \ @@ -2253,7 +3297,7 @@ } /* asc_enqueue() flags */ -#define ASC_FRONT 1 +#define ASC_FRONT 1 #define ASC_BACK 2 /* asc_dequeue_list() argument */ @@ -2316,6 +3360,7 @@ #define ASC_PCI_DEVICE_ID_1100 0x1100 #define ASC_PCI_DEVICE_ID_1200 0x1200 #define ASC_PCI_DEVICE_ID_1300 0x1300 +#define ASC_PCI_DEVICE_ID_2300 0x2300 /* PCI IO Port Addresses to generate special cycle */ @@ -2397,8 +3442,10 @@ #define ASC_DBG4(lvl, s, a1, a2, a3, a4) #define ASC_DBG_PRT_SCSI_HOST(lvl, s) #define ASC_DBG_PRT_SCSI_CMND(lvl, s) -#define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) -#define ASC_DBG_PRT_QDONE_INFO(lvl, qdone) +#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) +#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) +#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) +#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) #define ASC_DBG_PRT_HEX(lvl, name, start, length) #define ASC_DBG_PRT_CDB(lvl, cdb, len) #define ASC_DBG_PRT_SENSE(lvl, sense, len) @@ -2462,17 +3509,24 @@ } \ } -#define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) \ +#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \ + { \ + if (asc_dbglvl >= (lvl)) { \ + asc_prt_asc_scsi_q(scsiqp); \ + } \ + } + +#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \ { \ if (asc_dbglvl >= (lvl)) { \ - asc_prt_scsi_q(scsiqp); \ + asc_prt_asc_qdone_info(qdone); \ } \ } -#define ASC_DBG_PRT_QDONE_INFO(lvl, qdone) \ +#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \ { \ if (asc_dbglvl >= (lvl)) { \ - asc_prt_qdone_info(qdone); \ + asc_prt_adv_scsi_req_q(scsiqp); \ } \ } @@ -2522,15 +3576,17 @@ ulong abort; /* # calls to advansys_abort() */ ulong reset; /* # calls to advansys_reset() */ ulong biosparam; /* # calls to advansys_biosparam() */ - ulong check_interrupt; /* # advansys_interrupt() check pending calls */ - ulong interrupt; /* # advansys_interrupt() interrupts */ - ulong callback; /* # calls asc_isr_callback() */ - ulong done; /* # calls request scsi_done */ - /* AscExeScsiQueue() Statistics */ - ulong asc_noerror; /* # AscExeScsiQueue() ASC_NOERROR returns. */ - ulong asc_busy; /* # AscExeScsiQueue() ASC_BUSY returns. */ - ulong asc_error; /* # AscExeScsiQueue() ASC_ERROR returns. */ - ulong asc_unknown; /* # AscExeScsiQueue() unknown returns. */ + ulong interrupt; /* # advansys_interrupt() calls */ + ulong callback; /* # calls to asc/adv_isr_callback() */ + ulong done; /* # calls to request's scsi_done function */ + ulong build_error; /* # asc/adv_build_req() ASC_ERROR returns. */ + ulong adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */ + ulong adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */ + /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */ + ulong exe_noerror; /* # ASC_NOERROR returns. */ + ulong exe_busy; /* # ASC_BUSY returns. */ + ulong exe_error; /* # ASC_ERROR returns. */ + ulong exe_unknown; /* # unknown returns. */ /* Data Transfer Statistics */ ulong cont_cnt; /* # non-scatter-gather I/O requests received */ ulong cont_xfer; /* # contiguous transfer 512-bytes */ @@ -2544,20 +3600,49 @@ * Request queuing structure */ typedef struct asc_queue { - ASC_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */ - REQP q_first[ASC_MAX_TID+1]; /* first queued request */ - REQP q_last[ASC_MAX_TID+1]; /* last queued request */ + ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */ + REQP q_first[ADV_MAX_TID+1]; /* first queued request */ + REQP q_last[ADV_MAX_TID+1]; /* last queued request */ #ifdef ADVANSYS_STATS - short q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */ - short q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */ - ulong q_tot_cnt[ASC_MAX_TID+1]; /* total enqueue count */ - ulong q_tot_tim[ASC_MAX_TID+1]; /* total time queued */ - ushort q_max_tim[ASC_MAX_TID+1]; /* maximum time queued */ - ushort q_min_tim[ASC_MAX_TID+1]; /* minimum time queued */ + short q_cur_cnt[ADV_MAX_TID+1]; /* current queue count */ + short q_max_cnt[ADV_MAX_TID+1]; /* maximum queue count */ + ulong q_tot_cnt[ADV_MAX_TID+1]; /* total enqueue count */ + ulong q_tot_tim[ADV_MAX_TID+1]; /* total time queued */ + ushort q_max_tim[ADV_MAX_TID+1]; /* maximum time queued */ + ushort q_min_tim[ADV_MAX_TID+1]; /* minimum time queued */ #endif /* ADVANSYS_STATS */ } asc_queue_t; /* + * Adv Library Request Structures + * + * The following two se structures are used to process Wide Board requests. + * One structure is needed for each command received from the Mid-Level SCSI + * driver. + * + * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library + * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the + * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the + * Mid-Level SCSI request structure. + * + * The adv_sgblk_t structure is used to handle requests that include + * scatter-gather elements. + */ +typedef struct adv_sgblk { + ADV_SG_BLOCK sg_block[ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING]; + uchar align2[4]; /* Sgblock structure padding. */ + struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */ +} adv_sgblk_t; + +typedef struct adv_req { + ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */ + uchar align1[4]; /* Request structure padding. */ + Scsi_Cmnd *cmndp; /* Mid-Level SCSI command pointer. */ + adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */ + struct adv_req *next_reqp; /* Next Request Structure. */ +} adv_req_t; + +/* * Structure allocated for each board. * * This structure is allocated by scsi_register() at the end @@ -2565,35 +3650,60 @@ * field. It is guaranteed to be allocated from DMA-able memory. */ typedef struct asc_board { - int id; /* Board Id */ - uint flags; /* Board flags */ - ASC_DVC_VAR asc_dvc_var; /* Board configuration */ - ASC_DVC_CFG asc_dvc_cfg; /* Device configuration */ - asc_queue_t active; /* Active command queue */ - asc_queue_t waiting; /* Waiting command queue */ - asc_queue_t done; /* Done command queue */ - ASC_SCSI_BIT_ID_TYPE init_tidmask; /* Target initialized mask */ - /* The following three structures must be in DMA-able memory. */ - ASC_SCSI_REQ_Q scsireqq; - ASC_CAP_INFO cap_info; - ASC_SCSI_INQUIRY inquiry; - Scsi_Device *device[ASC_MAX_TID+1]; /* Mid-Level Scsi Device */ - ushort reqcnt[ASC_MAX_TID+1]; /* Starvation request count */ - uchar sdtr_data[ASC_MAX_TID+1]; /* SDTR information */ + int id; /* Board Id */ + uint flags; /* Board flags */ + union { + ASC_DVC_VAR asc_dvc_var; /* Narrow board */ + ADV_DVC_VAR adv_dvc_var; /* Wide board */ + } dvc_var; + union { + ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */ + ADV_DVC_CFG adv_dvc_cfg; /* Wide board */ + } dvc_cfg; + asc_queue_t active; /* Active command queue */ + asc_queue_t waiting; /* Waiting command queue */ + asc_queue_t done; /* Done command queue */ + ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */ + Scsi_Device *device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */ + ushort reqcnt[ADV_MAX_TID+1]; /* Starvation request count */ #if ASC_QUEUE_FLOW_CONTROL - ushort nerrcnt[ASC_MAX_TID+1]; /* No error request count */ + ushort nerrcnt[ADV_MAX_TID+1]; /* No error request count */ #endif /* ASC_QUEUE_FLOW_CONTROL */ - ASC_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */ - ushort queue_full_cnt[ASC_MAX_TID+1]; /* Queue full count */ - ASCEEP_CONFIG eep_config; /* EEPROM configuration */ - ulong last_reset; /* Saved last reset time */ + ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */ + ushort queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */ + union { + ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */ + ADVEEP_CONFIG adv_eep; /* Wide EEPROM config. */ + } eep_config; + ulong last_reset; /* Saved last reset time */ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) /* /proc/scsi/advansys/[0...] */ - char *prtbuf; /* Statistics Print Buffer */ + char *prtbuf; /* Statistics Print Buffer */ #endif /* version >= v1.3.0 */ #ifdef ADVANSYS_STATS - struct asc_stats asc_stats; /* Board statistics */ + struct asc_stats asc_stats; /* Board statistics */ #endif /* ADVANSYS_STATS */ + /* + * The following fields are used only for Narrow Boards. + */ + /* The following three structures must be in DMA-able memory. */ + ASC_SCSI_REQ_Q scsireqq; + ASC_CAP_INFO cap_info; + ASC_SCSI_INQUIRY inquiry; + uchar sdtr_data[ASC_MAX_TID+1]; /* SDTR information */ + /* + * The following fields are used only for Wide Boards. + */ + void *ioremap_addr; /* I/O Memory remap address. */ + ushort ioport; /* I/O Port address. */ + adv_req_t *orig_reqp; /* adv_req_t memory block. */ + adv_req_t *adv_reqp; /* Request structures. */ + adv_sgblk_t *orig_sgblkp; /* adv_sgblk_t memory block. */ + adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */ + ushort bios_signature; /* BIOS Signature. */ + ushort bios_version; /* BIOS Version. */ + ushort bios_codeseg; /* BIOS Code Segment. */ + ushort bios_codelen; /* BIOS Code Segment Length. */ } asc_board_t; /* @@ -2655,10 +3765,10 @@ #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) struct proc_dir_entry proc_scsi_advansys = { - PROC_SCSI_ADVANSYS, /* unsigned short low_ino */ - 8, /* unsigned short namelen */ - "advansys", /* const char *name */ - S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */ + PROC_SCSI_ADVANSYS, /* unsigned short low_ino */ + 8, /* unsigned short namelen */ + "advansys", /* const char *name */ + S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */ 2 /* nlink_t nlink */ }; #endif /* version >= v1.3.0 */ @@ -2691,7 +3801,18 @@ * limit I/O port probing at boot time, cf. advansys_setup(). */ STATIC int asc_iopflag = ASC_FALSE; -STATIC int asc_ioport[ASC_NUM_BOARD_SUPPORTED] = { 0, 0, 0, 0 }; +STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 }; + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) +/* + * In kernels earlier than v1.3.0, kmalloc() does not work + * during driver initialization. Therefore statically declare + * 16 elements of each structure. v1.3.0 kernels will probably + * not need any more than this number. + */ +uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 }; +uchar adv_sgblk_buf[16 * sizeof(adv_sgblk_t)] = { 0 }; +#endif /* version >= v1,3,0 */ #ifdef ADVANSYS_DEBUG STATIC char * @@ -2727,47 +3848,59 @@ STATIC void advansys_select_queue_depths(struct Scsi_Host *, Scsi_Device *); #endif /* version >= v1.3.89 */ -STATIC void advansys_command_done(Scsi_Cmnd *); -STATIC void asc_scsi_done_list(Scsi_Cmnd *); -STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); -STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); -STATIC int asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *); -STATIC int asc_srch_pci_dev(PCI_DEVICE *); -STATIC uchar asc_scan_method(void); -STATIC int asc_pci_find_dev(PCI_DEVICE *); -STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *); -STATIC ushort asc_get_cfg_word(PCI_DATA *); -STATIC uchar asc_get_cfg_byte(PCI_DATA *); -STATIC void asc_put_cfg_byte(PCI_DATA *, uchar); -STATIC void asc_enqueue(asc_queue_t *, REQP, int); -STATIC REQP asc_dequeue(asc_queue_t *, int); -STATIC REQP asc_dequeue_list(asc_queue_t *, REQP *, int); -STATIC int asc_rmqueue(asc_queue_t *, REQP); -STATIC int asc_isqueued(asc_queue_t *, REQP); -STATIC void asc_execute_queue(asc_queue_t *); +STATIC void advansys_command_done(Scsi_Cmnd *); +STATIC void asc_scsi_done_list(Scsi_Cmnd *); +STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); +STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *); +STATIC int adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **); +STATIC int adv_get_sglist(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, Scsi_Cmnd *); +STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); +STATIC void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *); +STATIC int asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *); +STATIC int asc_srch_pci_dev(PCI_DEVICE *); +STATIC uchar asc_scan_method(void); +STATIC int asc_pci_find_dev(PCI_DEVICE *); +STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *); +STATIC ushort asc_get_cfg_word(PCI_DATA *); +STATIC uchar asc_get_cfg_byte(PCI_DATA *); +STATIC void asc_put_cfg_byte(PCI_DATA *, uchar); +STATIC void asc_enqueue(asc_queue_t *, REQP, int); +STATIC REQP asc_dequeue(asc_queue_t *, int); +STATIC REQP asc_dequeue_list(asc_queue_t *, REQP *, int); +STATIC int asc_rmqueue(asc_queue_t *, REQP); +STATIC int asc_isqueued(asc_queue_t *, REQP); +STATIC void asc_execute_queue(asc_queue_t *); #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) -STATIC int asc_prt_board_devices(struct Scsi_Host *, char *, int); -STATIC int asc_prt_board_eeprom(struct Scsi_Host *, char *, int); -STATIC int asc_prt_driver_conf(struct Scsi_Host *, char *, int); -STATIC int asc_prt_board_info(struct Scsi_Host *, char *, int); -STATIC int asc_prt_line(char *, int, char *fmt, ...); +STATIC int asc_prt_board_devices(struct Scsi_Host *, char *, int); +STATIC int asc_prt_adv_bios(struct Scsi_Host *, char *, int); +STATIC int asc_get_eeprom_string(ushort *serialnum, uchar *cp); +STATIC int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int); +STATIC int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int); +STATIC int asc_prt_driver_conf(struct Scsi_Host *, char *, int); +STATIC int asc_prt_asc_board_info(struct Scsi_Host *, char *, int); +STATIC int asc_prt_adv_board_info(struct Scsi_Host *, char *, int); +STATIC int asc_prt_line(char *, int, char *fmt, ...); #endif /* version >= v1.3.0 */ /* Declaration for Asc Library internal functions reference by driver. */ -STATIC int AscFindSignature(PortAddr); -STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); +STATIC int AscFindSignature(PortAddr); +STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); #ifdef ADVANSYS_STATS -STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int); +STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int); #endif /* ADVANSYS_STATS */ #ifdef ADVANSYS_DEBUG STATIC void asc_prt_scsi_host(struct Scsi_Host *); STATIC void asc_prt_scsi_cmnd(Scsi_Cmnd *); -STATIC void asc_prt_dvc_cfg(ASC_DVC_CFG *); -STATIC void asc_prt_dvc_var(ASC_DVC_VAR *); -STATIC void asc_prt_scsi_q(ASC_SCSI_Q *); -STATIC void asc_prt_qdone_info(ASC_QDONE_INFO *); +STATIC void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *); +STATIC void asc_prt_asc_dvc_var(ASC_DVC_VAR *); +STATIC void asc_prt_asc_scsi_q(ASC_SCSI_Q *); +STATIC void asc_prt_asc_qdone_info(ASC_QDONE_INFO *); +STATIC void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *); +STATIC void asc_prt_adv_dvc_var(ADV_DVC_VAR *); +STATIC void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *); +STATIC void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *); STATIC void asc_prt_hex(char *f, uchar *, int); #endif /* ADVANSYS_DEBUG */ @@ -2815,7 +3948,7 @@ int leftlen; char *curbuf; off_t advoffset; - Scsi_Device *scd = NULL; + Scsi_Device *scd; ASC_DBG(1, "advansys_proc_info: begin\n"); @@ -2870,6 +4003,24 @@ curbuf += cnt; /* + * Display Wide Board BIOS Information. + */ + if (ASC_WIDE_BOARD(boardp)) { + cp = boardp->prtbuf; + cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + } + + /* * Display driver information for each device attached to the board. */ cp = boardp->prtbuf; @@ -2889,7 +4040,13 @@ * Display target driver information for each device attached * to the board. */ - for (scd = scd->host->host_queue; scd; scd = scd->next) { +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75) + for (scd = scsi_devices; scd; scd = scd->next) +#else /* version >= v2.1.75 */ + for (scd = shp->host_queue; scd; scd = scd->next) +#endif /* version >= v2.1.75 */ + { + if (scd->host == shp) { cp = boardp->prtbuf; /* * Note: If proc_print_scsidevice() writes more than @@ -2906,13 +4063,18 @@ } advoffset += cplen; curbuf += cnt; + } } /* * Display EEPROM configuration for the board. */ cp = boardp->prtbuf; - cplen = asc_prt_board_eeprom(shp, cp, ASC_PRTBUF_SIZE); + if (ASC_NARROW_BOARD(boardp)) { + cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE); + } else { + cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE); + } ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; @@ -2963,8 +4125,12 @@ * for the board. */ cp = boardp->prtbuf; - cplen = asc_prt_board_info(shp, cp, ASC_PRTBUF_SIZE); - ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); + if (ASC_NARROW_BOARD(boardp)) { + cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE); + } else { + cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE); + } + ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; leftlen -= cnt; @@ -2981,7 +4147,6 @@ } #endif /* version >= v1.3.0 */ - /* * advansys_detect() * @@ -3005,17 +4170,19 @@ int bus; struct Scsi_Host *shp; asc_board_t *boardp; - ASC_DVC_VAR *asc_dvc_varp; + ASC_DVC_VAR *asc_dvc_varp = NULL; + ADV_DVC_VAR *adv_dvc_varp = NULL; int ioport = 0; int share_irq = FALSE; PCI_DEVICE pciDevice; PCI_CONFIG_SPACE pciConfig; + int warn_code, err_code; int ret; if (detect_called == ASC_FALSE) { detect_called = ASC_TRUE; } else { - printk("AdvanSys SCSI: advansys_detect() mulitple calls ignored\n"); + printk("AdvanSys SCSI: advansys_detect() multiple calls ignored\n"); return 0; } @@ -3032,7 +4199,7 @@ * clean-up the 'asc_ioport' list. */ if (asc_iopflag == ASC_TRUE) { - for (ioport = 0; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) { + for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) { ASC_DBG2(1, "advansys_detect: asc_ioport[%d] %x\n", ioport, asc_ioport[ioport]); if (asc_ioport[ioport] != 0) { @@ -3042,7 +4209,8 @@ } } if (iop == ASC_IOADR_TABLE_MAX_IX) { - printk("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n", + printk( +"AdvanSys SCSI: specified I/O Port 0x%X is invalid\n", asc_ioport[ioport]); asc_ioport[ioport] = 0; } @@ -3082,7 +4250,7 @@ ASC_DBG(1, "advansys_detect: I/O port scanning modified\n"); ioport_try_again: iop = 0; - for (; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) { + for (; ioport < ASC_NUM_IOPORT_PROBE; ioport++) { if ((iop = asc_ioport[ioport]) != 0) { break; } @@ -3091,12 +4259,14 @@ ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n", iop); if (check_region(iop, ASC_IOADR_GAP) != 0) { - printk("AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop); + printk( +"AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop); /* Don't try this I/O port twice. */ asc_ioport[ioport] = 0; goto ioport_try_again; } else if (AscFindSignature(iop) == ASC_FALSE) { - printk("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop); + printk( +"AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop); /* Don't try this I/O port twice. */ asc_ioport[ioport] = 0; goto ioport_try_again; @@ -3142,7 +4312,10 @@ pciDevice.slotFound, pciDevice.busNumber); asc_get_pci_cfg(&pciDevice, &pciConfig); iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK; - ASC_DBG2(2, "advansys_detect: iop %x, irqLine %d\n", + ASC_DBG2(1, + "advansys_detect: vendorID %X, deviceID %X\n", + pciConfig.vendorID, pciConfig.deviceID); + ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n", iop, pciConfig.irqLine); } break; @@ -3177,13 +4350,76 @@ boardp = ASC_BOARDP(shp); memset(boardp, 0, sizeof(asc_board_t)); boardp->id = asc_board_count - 1; - asc_dvc_varp = &boardp->asc_dvc_var; - asc_dvc_varp->drv_ptr = (ulong) boardp; - asc_dvc_varp->cfg = &boardp->asc_dvc_cfg; - asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0]; - asc_dvc_varp->iop_base = iop; + + /* + * Handle both narrow and wide PCI boards. + * + * If a Wide board was detected, set the board structure + * wide board flag. Set-up the board structure based on + * the board type. + */ + if ((asc_bus[bus] == ASC_IS_PCI && + pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) == 0) { + ASC_DBG(1, "advansys_detect: narrow board\n"); + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + asc_dvc_varp->bus_type = asc_bus[bus]; + asc_dvc_varp->drv_ptr = (ulong) boardp; + asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg; + asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0]; + asc_dvc_varp->iop_base = iop; + asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback; + } else { + ASC_DBG(1, "advansys_detect: wide board\n"); + boardp->flags |= ASC_IS_WIDE_BOARD; + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + adv_dvc_varp->drv_ptr = (ulong) boardp; + adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg; + adv_dvc_varp->isr_callback = (Ptr2Func) adv_isr_callback; + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) + adv_dvc_varp->iop_base = iop; +#else /* version >= v1,3,0 */ + /* + * Map the board's registers into virtual memory for + * PCI slave access. Only memory accesses are used to + * access the board's registers. + * + * Note: The PCI register base address is not always + * page aligned, but the address passed to ioremap() + * must be page aligned. It is guaranteed that the + * PCI register base address will not cross a page + * boundary. + */ + if ((boardp->ioremap_addr = + ioremap(pciConfig.baseAddress[1] & PAGE_MASK, + PAGE_SIZE)) == 0) { + ASC_PRINT3( +"advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n", + boardp->id, pciConfig.baseAddress[1], ADV_CONDOR_IOLEN); + scsi_unregister(shp); + asc_board_count--; + continue; + } + adv_dvc_varp->iop_base = (AdvPortAddr) + (boardp->ioremap_addr + + (pciConfig.baseAddress[1] - + (pciConfig.baseAddress[1] & PAGE_MASK))); +#endif /* version >= v1,3,0 */ + + /* + * Even though it isn't used to access the board in + * kernels greater than or equal to v1.3.0, save + * the I/O Port address so that it can be reported and + * displayed. + */ + boardp->ioport = iop; + } #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + /* + * Allocate buffer for printing information from + * /proc/scsi/advansys/[0...]. + */ if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) { ASC_PRINT3( @@ -3195,90 +4431,122 @@ } #endif /* version >= v1.3.0 */ - /* - * Set the board bus type and PCI IRQ for AscInitGetConfig(). - */ - asc_dvc_varp->bus_type = asc_bus[bus]; - switch (asc_dvc_varp->bus_type) { - case ASC_IS_ISA: - shp->unchecked_isa_dma = TRUE; - share_irq = FALSE; - break; - case ASC_IS_VL: - shp->unchecked_isa_dma = FALSE; - share_irq = FALSE; - break; - case ASC_IS_EISA: - shp->unchecked_isa_dma = FALSE; - share_irq = TRUE; - break; - case ASC_IS_PCI: - shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine; - asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; - asc_dvc_varp->cfg->pci_slot_info = + if (ASC_NARROW_BOARD(boardp)) { + /* + * Set the board bus type and PCI IRQ before + * calling AscInitGetConfig(). + */ + switch (asc_dvc_varp->bus_type) { + case ASC_IS_ISA: + shp->unchecked_isa_dma = TRUE; + share_irq = FALSE; + break; + case ASC_IS_VL: + shp->unchecked_isa_dma = FALSE; + share_irq = FALSE; + break; + case ASC_IS_EISA: + shp->unchecked_isa_dma = FALSE; + share_irq = TRUE; + break; + case ASC_IS_PCI: + shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine; + shp->unchecked_isa_dma = FALSE; + share_irq = TRUE; + asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; + asc_dvc_varp->cfg->pci_slot_info = ASC_PCI_MKID(pciDevice.busNumber, - pciDevice.slotFound, - pciDevice.devFunc); + pciDevice.slotFound, + pciDevice.devFunc); + break; + default: + ASC_PRINT2( +"advansys_detect: board %d: unknown adapter type: %d\n", + boardp->id, asc_dvc_varp->bus_type); + shp->unchecked_isa_dma = TRUE; + share_irq = FALSE; + break; + } + } else { + /* + * For Wide boards set PCI information before calling + * AdvInitGetConfig(). + */ + shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine; shp->unchecked_isa_dma = FALSE; share_irq = TRUE; - break; - default: - ASC_PRINT2( -"advansys_detect: board %d: unknown adapter type: %d", - boardp->id, asc_dvc_varp->bus_type); - shp->unchecked_isa_dma = TRUE; - share_irq = FALSE; - break; + adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; + adv_dvc_varp->cfg->pci_slot_info = + ASC_PCI_MKID(pciDevice.busNumber, + pciDevice.slotFound, + pciDevice.devFunc); } /* - * Get the board configuration. - * - * NOTE: AscInitGetConfig() may change the board's bus_type - * value. The asc_bus[bus] value should no longer be used. If - * the bus_type field must be referenced only use the bit-wise - * AND operator "&". + * Read the board configuration. */ - ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n"); - switch(ret = AscInitGetConfig(asc_dvc_varp)) { - case 0: /* No error */ - break; - case ASC_WARN_IO_PORT_ROTATE: - ASC_PRINT1( + if (ASC_NARROW_BOARD(boardp)) { + /* + * NOTE: AscInitGetConfig() may change the board's + * bus_type value. The asc_bus[bus] value should no + * longer be used. If the bus_type field must be + * referenced only use the bit-wise AND operator "&". + */ + ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n"); + switch(ret = AscInitGetConfig(asc_dvc_varp)) { + case 0: /* No error */ + break; + case ASC_WARN_IO_PORT_ROTATE: + ASC_PRINT1( "AscInitGetConfig: board %d: I/O port address modified\n", - boardp->id); - break; - case ASC_WARN_AUTO_CONFIG: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_AUTO_CONFIG: + ASC_PRINT1( "AscInitGetConfig: board %d: I/O port increment switch enabled\n", - boardp->id); - break; - case ASC_WARN_EEPROM_CHKSUM: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_EEPROM_CHKSUM: + ASC_PRINT1( "AscInitGetConfig: board %d: EEPROM checksum error\n", - boardp->id); - break; - case ASC_WARN_IRQ_MODIFIED: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_IRQ_MODIFIED: + ASC_PRINT1( "AscInitGetConfig: board %d: IRQ modified\n", - boardp->id); - break; - case ASC_WARN_CMD_QNG_CONFLICT: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_CMD_QNG_CONFLICT: + ASC_PRINT1( "AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n", - boardp->id); - break; - default: - ASC_PRINT2( + boardp->id); + break; + default: + ASC_PRINT2( "AscInitGetConfig: board %d: unknown warning: %x\n", - boardp->id, ret); - break; - } - if (asc_dvc_varp->err_code != 0) { - ASC_PRINT3( + boardp->id, ret); + break; + } + if ((err_code = asc_dvc_varp->err_code) != 0) { + ASC_PRINT3( "AscInitGetConfig: board %d error: init_state %x, err_code %x\n", - boardp->id, asc_dvc_varp->init_state, - asc_dvc_varp->err_code); + boardp->id, asc_dvc_varp->init_state, + asc_dvc_varp->err_code); + } + } else { + ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n"); + if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) { + ASC_PRINT2("AdvInitGetConfig: board %d: warning: %x\n", + boardp->id, ret); + } + if ((err_code = adv_dvc_varp->err_code) != 0) { + ASC_PRINT2( +"AdvInitGetConfig: board %d error: err_code %x\n", + boardp->id, adv_dvc_varp->err_code); + } + } + + if (err_code != 0) { #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) kfree(boardp->prtbuf); #endif /* version >= v1.3.0 */ @@ -3288,110 +4556,180 @@ } /* - * Set the adapter's target id bit in the init_tidmask field. + * Save the EEPROM configuration so that it can be displayed + * from /proc/scsi/advansys/[0...]. */ - boardp->init_tidmask |= - ASC_TIX_TO_TARGET_ID(asc_dvc_varp->cfg->chip_scsi_id); + if (ASC_NARROW_BOARD(boardp)) { - /* - * Save EEPROM settings for the board. - */ - boardp->eep_config.init_sdtr = asc_dvc_varp->init_sdtr; - boardp->eep_config.disc_enable = asc_dvc_varp->cfg->disc_enable; - boardp->eep_config.use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled; - boardp->eep_config.isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed; - boardp->eep_config.start_motor = asc_dvc_varp->start_motor; - boardp->eep_config.cntl = asc_dvc_varp->dvc_cntl; - boardp->eep_config.no_scam = asc_dvc_varp->no_scam; - boardp->eep_config.max_total_qng = asc_dvc_varp->max_total_qng; - boardp->eep_config.chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id; - /* 'max_tag_qng' is set to the same value for every device. */ - boardp->eep_config.max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0]; + ASCEEP_CONFIG *ep; - /* - * Modify board configuration. - */ - asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback; - asc_dvc_varp->exe_callback = (Ptr2Func) NULL; + /* + * Set the adapter's target id bit in the 'init_tidmask' field. + */ + boardp->init_tidmask |= + ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id); - ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n"); - switch (ret = AscInitSetConfig(asc_dvc_varp)) { - case 0: /* No error. */ - break; - case ASC_WARN_IO_PORT_ROTATE: - ASC_PRINT1( + /* + * Save EEPROM settings for the board. + */ + ep = &boardp->eep_config.asc_eep; + + ep->init_sdtr = asc_dvc_varp->init_sdtr; + ep->disc_enable = asc_dvc_varp->cfg->disc_enable; + ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled; + ep->isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed; + ep->start_motor = asc_dvc_varp->start_motor; + ep->cntl = asc_dvc_varp->dvc_cntl; + ep->no_scam = asc_dvc_varp->no_scam; + ep->max_total_qng = asc_dvc_varp->max_total_qng; + ep->chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id; + /* 'max_tag_qng' is set to the same value for every device. */ + ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0]; + ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0]; + ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1]; + ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2]; + ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3]; + ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4]; + ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5]; + ep->adapter_info[6] = asc_dvc_varp->cfg->adapter_info[6]; + + /* + * Modify board configuration. + */ + ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n"); + switch (ret = AscInitSetConfig(asc_dvc_varp)) { + case 0: /* No error. */ + break; + case ASC_WARN_IO_PORT_ROTATE: + ASC_PRINT1( "AscInitSetConfig: board %d: I/O port address modified\n", - boardp->id); - break; - case ASC_WARN_AUTO_CONFIG: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_AUTO_CONFIG: + ASC_PRINT1( "AscInitSetConfig: board %d: I/O port increment switch enabled\n", - boardp->id); - break; - case ASC_WARN_EEPROM_CHKSUM: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_EEPROM_CHKSUM: + ASC_PRINT1( "AscInitSetConfig: board %d: EEPROM checksum error\n", - boardp->id); - break; - case ASC_WARN_IRQ_MODIFIED: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_IRQ_MODIFIED: + ASC_PRINT1( "AscInitSetConfig: board %d: IRQ modified\n", - boardp->id); - break; - case ASC_WARN_CMD_QNG_CONFLICT: - ASC_PRINT1( + boardp->id); + break; + case ASC_WARN_CMD_QNG_CONFLICT: + ASC_PRINT1( "AscInitSetConfig: board %d: tag queuing w/o disconnects\n", - boardp->id); - break; - default: - ASC_PRINT2( + boardp->id); + break; + default: + ASC_PRINT2( "AscInitSetConfig: board %d: unknown warning: %x\n", - boardp->id, ret); - break; - } - if (asc_dvc_varp->err_code != 0) { - ASC_PRINT3( + boardp->id, ret); + break; + } + if (asc_dvc_varp->err_code != 0) { + ASC_PRINT3( "AscInitSetConfig: board %d error: init_state %x, err_code %x\n", - boardp->id, asc_dvc_varp->init_state, - asc_dvc_varp->err_code); + boardp->id, asc_dvc_varp->init_state, + asc_dvc_varp->err_code); #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - kfree(boardp->prtbuf); + kfree(boardp->prtbuf); #endif /* version >= v1.3.0 */ - scsi_unregister(shp); - asc_board_count--; - continue; - } + scsi_unregister(shp); + asc_board_count--; + continue; + } - /* - * Finish initializing the 'Scsi_Host' structure. - */ + /* + * Finish initializing the 'Scsi_Host' structure. + */ + /* AscInitSetConfig() will set the IRQ for non-PCI boards. */ + if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) { + shp->irq = asc_dvc_varp->irq_no; + } + } else { + + ADVEEP_CONFIG *ep; + + /* + * Save Wide EEP Configuration Information. + */ + ep = &boardp->eep_config.adv_eep; + + ep->adapter_scsi_id = adv_dvc_varp->chip_scsi_id; + ep->max_host_qng = adv_dvc_varp->max_host_qng; + ep->max_dvc_qng = adv_dvc_varp->max_dvc_qng; + ep->termination = adv_dvc_varp->cfg->termination; + ep->disc_enable = adv_dvc_varp->cfg->disc_enable; + ep->bios_ctrl = adv_dvc_varp->bios_ctrl; + ep->wdtr_able = adv_dvc_varp->wdtr_able; + ep->sdtr_able = adv_dvc_varp->sdtr_able; + ep->ultra_able = adv_dvc_varp->ultra_able; + ep->tagqng_able = adv_dvc_varp->tagqng_able; + ep->start_motor = adv_dvc_varp->start_motor; + ep->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait; + ep->bios_boot_delay = adv_dvc_varp->cfg->bios_boot_wait; + ep->serial_number_word1 = adv_dvc_varp->cfg->serial1; + ep->serial_number_word2 = adv_dvc_varp->cfg->serial2; + ep->serial_number_word3 = adv_dvc_varp->cfg->serial3; + + /* + * Set the adapter's target id bit in the 'init_tidmask' field. + */ + boardp->init_tidmask |= + ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id); - /* AscInitSetConfig() will set the IRQ for non-PCI boards. */ - if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) { - shp->irq = asc_dvc_varp->irq_no; + /* + * Finish initializing the 'Scsi_Host' structure. + */ + shp->irq = adv_dvc_varp->irq_no; } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) /* - * One host supports one channel. There are two different - * hosts for each channel of a dual channel board. + * Channels are numbered beginning with 0. For AdvanSys One host + * structure supports one channel. Multi-channel boards have a + * separate host structure for each channel. */ -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) shp->max_channel = 0; #endif /* version >= v1.3.89 */ - shp->max_id = ASC_MAX_TID + 1; - shp->max_lun = ASC_MAX_LUN + 1; + if (ASC_NARROW_BOARD(boardp)) { + shp->max_id = ASC_MAX_TID + 1; + shp->max_lun = ASC_MAX_LUN + 1; + + shp->io_port = asc_dvc_varp->iop_base; + shp->n_io_port = ASC_IOADR_GAP; + shp->this_id = asc_dvc_varp->cfg->chip_scsi_id; + + /* Set maximum number of queues the adapter can handle. */ + shp->can_queue = asc_dvc_varp->max_total_qng; + } else { + shp->max_id = ADV_MAX_TID + 1; + shp->max_lun = ADV_MAX_LUN + 1; + + /* + * Save the I/O Port address and length even though the + * in v1.3.0 and greater kernels the region is not used + * by a Wide board. Instead the board is accessed with + * Memory Mapped I/O. + */ + shp->io_port = iop; + shp->n_io_port = ADV_CONDOR_IOLEN; - shp->io_port = asc_dvc_varp->iop_base; - shp->n_io_port = ASC_IOADR_GAP; - shp->this_id = asc_dvc_varp->cfg->chip_scsi_id; + shp->this_id = adv_dvc_varp->chip_scsi_id; - /* Maximum number of queues this adapter can handle. */ - shp->can_queue = asc_dvc_varp->max_total_qng; + /* Set maximum number of queues the adapter can handle. */ + shp->can_queue = adv_dvc_varp->max_host_qng; + } #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) /* - * Set a conservative 'cmd_per_lun' value to prevent memory - * allocation failures. + * In old kernels without tag queuing support and with memory + * allocation problems set a conservative 'cmd_per_lun' value. */ #ifdef MODULE shp->cmd_per_lun = 1; @@ -3401,54 +4739,54 @@ ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun); #else /* version >= v1.3.89 */ /* - * Use the host 'select_queue_depths' function to determine - * the number of commands to queue per device. + * Following v1.3.89, 'cmd_per_lun' is no longer needed + * and should be set to zero. + * + * But because of a bug introduced in v1.3.89 if the driver is + * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level + * SCSI function 'allocate_device' will panic. To allow the driver + * to work as a module in these kernels set 'cmd_per_lun' to 1. */ - shp->select_queue_depths = advansys_select_queue_depths; - #ifdef MODULE - /* - * FIXME(eric) - this is completely bogus. We need to - * figure out what exactly the real problem is and deal - * with it. - */ - /* - * Following v1.3.89, 'cmd_per_lun' is no longer needed - * and should be set to zero. But because of a bug introduced - * in v1.3.89 if the driver is compiled as a module and - * 'cmd_per_lun' is zero, the Mid-Level SCSI function - * 'scsi_allocate_device' will panic. To allow the driver to - * work as a module in these kernels set 'cmd_per_lun' to 1. - */ - shp->cmd_per_lun = 1; + shp->cmd_per_lun = 1; #else /* MODULE */ shp->cmd_per_lun = 0; #endif /* MODULE */ + /* + * Use the host 'select_queue_depths' function to determine + * the number of commands to queue per device. + */ + shp->select_queue_depths = advansys_select_queue_depths; #endif /* version >= v1.3.89 */ /* - * Set the maximum number of scatter-gather elements adapter - * can handle. + * Set the maximum number of scatter-gather elements the + * adapter can handle. */ + if (ASC_NARROW_BOARD(boardp)) { + /* + * Allow two commands with 'sg_tablesize' scatter-gather + * elements to be executed simultaneously. This value is + * the theoretical hardware limit. It may be decreased + * below. + */ + shp->sg_tablesize = + (((asc_dvc_varp->max_total_qng - 2) / 2) * + ASC_SG_LIST_PER_Q) + 1; + } else { + shp->sg_tablesize = ADV_MAX_SG_LIST; + } #ifdef MODULE /* - * If the driver is compiled as a module, set a conservative + * If the driver is compiled as a module, set a limit on the * 'sg_tablesize' value to prevent memory allocation failures. * Memory allocation errors are more likely to occur at module * load time, then at driver initialization time. */ - shp->sg_tablesize = 8; -#else /* MODULE */ - /* - * Allow two commands with 'sg_tablesize' scatter-gather - * elements to be executed simultaneously. This value is - * the theoretical hardware limit. It may be decreased - * below. - */ - shp->sg_tablesize = - (((asc_dvc_varp->max_total_qng - 2) / 2) * - ASC_SG_LIST_PER_Q) + 1; + if (shp->sg_tablesize > 64) { + shp->sg_tablesize = 64; + } #endif /* MODULE */ /* @@ -3465,52 +4803,96 @@ shp->sg_tablesize); /* BIOS start address. */ - shp->base = (char *) ((ulong) AscGetChipBiosAddress( + if (ASC_NARROW_BOARD(boardp)) { + shp->base = (char *) ((ulong) AscGetChipBiosAddress( asc_dvc_varp->iop_base, asc_dvc_varp->bus_type)); + } else { + /* + * Fill-in BIOS board variables. The Wide BIOS saves + * information in LRAM that is used by the driver. + */ + AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_SIGNATURE, + boardp->bios_signature); + AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_VERSION, + boardp->bios_version); + AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODESEG, + boardp->bios_codeseg); + AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODELEN, + boardp->bios_codelen); + + ASC_DBG2(1, + "advansys_detect: bios_signature %x, bios_version %x\n", + boardp->bios_signature, boardp->bios_version); + + ASC_DBG2(1, + "advansys_detect: bios_codeseg %x, bios_codelen %x\n", + boardp->bios_codeseg, boardp->bios_codelen); + + /* + * If the BIOS saved a valid signature, then fill in + * the BIOS code segment base address. + */ + if (boardp->bios_signature == 0x55AA) { + /* + * Convert x86 realmode code segment to a linear + * address by shifting left 4. + */ + shp->base = (uchar *) (boardp->bios_codeseg << 4); + } else { + shp->base = 0; + } + } /* * Register Board Resources - I/O Port, DMA, IRQ */ - /* Register I/O port range */ + /* Register I/O port range. */ ASC_DBG(2, "advansys_detect: request_region()\n"); request_region(shp->io_port, shp->n_io_port, "advansys"); - /* Register DMA channel for ISA bus. */ - if ((asc_dvc_varp->bus_type & ASC_IS_ISA) == 0) { - shp->dma_channel = NO_ISA_DMA; - } else { - shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel; - if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) { - ASC_PRINT3( + /* Register DMA Channel for Narrow boards. */ + shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */ + if (ASC_NARROW_BOARD(boardp)) { + /* Register DMA channel for ISA bus. */ + if (asc_dvc_varp->bus_type & ASC_IS_ISA) { + shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel; + if ((ret = + request_dma(shp->dma_channel, "advansys")) != 0) { + ASC_PRINT3( "advansys_detect: board %d: request_dma() %d failed %d\n", - boardp->id, shp->dma_channel, ret); - release_region(shp->io_port, shp->n_io_port); + boardp->id, shp->dma_channel, ret); + release_region(shp->io_port, shp->n_io_port); #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) - kfree(boardp->prtbuf); + kfree(boardp->prtbuf); #endif /* version >= v1.3.0 */ - scsi_unregister(shp); - asc_board_count--; - continue; + scsi_unregister(shp); + asc_board_count--; + continue; + } + AscEnableIsaDma(shp->dma_channel); } - AscEnableIsaDma(shp->dma_channel); } /* Register IRQ Number. */ ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq); #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) if ((ret = request_irq(shp->irq, advansys_interrupt, - SA_INTERRUPT, "advansys")) != 0) { + SA_INTERRUPT, "advansys")) != 0) #else /* version >= v1.3.70 */ if ((ret = request_irq(shp->irq, advansys_interrupt, SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0), - "advansys", boardp)) != 0) { + "advansys", boardp)) != 0) #endif /* version >= v1.3.70 */ + { ASC_PRINT2( "advansys_detect: board %d: request_irq() failed %d\n", boardp->id, ret); release_region(shp->io_port, shp->n_io_port); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + iounmap(boardp->ioremap_addr); +#endif /* version >= v1,3,0 */ if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } @@ -3525,13 +4907,146 @@ /* * Initialize board RISC chip and enable interrupts. */ - ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n"); - if (AscInitAsc1000Driver(asc_dvc_varp)) { - ASC_PRINT3( -"AscInitAsc1000Driver: board %d: error: init_state %x, err_code %x\n", - boardp->id, asc_dvc_varp->init_state, - asc_dvc_varp->err_code); + if (ASC_NARROW_BOARD(boardp)) { + ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n"); + warn_code = AscInitAsc1000Driver(asc_dvc_varp); + err_code = asc_dvc_varp->err_code; + + if (warn_code || err_code) { + ASC_PRINT4( +"AscInitAsc1000Driver: board %d: error: init_state %x, warn %x error %x\n", + boardp->id, asc_dvc_varp->init_state, + warn_code, err_code); + } + } else { + int req_cnt; + adv_req_t *reqp = NULL; + int sg_cnt; + adv_sgblk_t *sgp = NULL; + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) + req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t); + sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t); + reqp = (adv_req_t *) &adv_req_buf[0]; + sgp = (adv_sgblk_t *) &adv_sgblk_buf[0]; +#else /* version >= v1.3.0 */ + /* + * Allocate up to 'max_host_qng' request structures for + * the Wide board. + */ + for (req_cnt = adv_dvc_varp->max_host_qng; + req_cnt > 0; req_cnt--) { + + reqp = (adv_req_t *) + kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC); + + ASC_DBG3(1, + "advansys_detect: reqp %x, req_cnt %d, bytes %d\n", + (unsigned) reqp, req_cnt, sizeof(adv_req_t) * req_cnt); + + if (reqp != NULL) { + break; + } + } + + /* + * Allocate up to ADV_TOT_SG_LIST request structures for + * the Wide board. + */ + for (sg_cnt = ADV_TOT_SG_LIST; sg_cnt > 0; sg_cnt--) { + + sgp = (adv_sgblk_t *) + kmalloc(sizeof(adv_sgblk_t) * sg_cnt, GFP_ATOMIC); + + ASC_DBG3(1, + "advansys_detect: sgp %x, sg_cnt %d, bytes %d\n", + (unsigned) sgp, sg_cnt, sizeof(adv_sgblk_t) * sg_cnt); + + if (sgp != NULL) { + break; + } + } +#endif /* version >= v1.3.0 */ + + /* + * If no request structures or scatter-gather structures could + * be allocated, then return an error. Otherwise continue with + * initialization. + */ + if (reqp == NULL) { + ASC_PRINT1( +"advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n", + boardp->id); + err_code = ADV_ERROR; + } else if (sgp == NULL) { + kfree(reqp); + ASC_PRINT1( +"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffer.\n", + boardp->id); + err_code = ADV_ERROR; + } else { + + /* + * Save original pointer for kfree() in case the + * driver is built as a module and can be unloaded. + */ + boardp->orig_reqp = reqp; + + /* + * Point 'adv_reqp' to the request structures and + * link them together. + */ + req_cnt--; + reqp[req_cnt].next_reqp = NULL; + for (; req_cnt > 0; req_cnt--) { + reqp[req_cnt - 1].next_reqp = &reqp[req_cnt]; + } + boardp->adv_reqp = &reqp[0]; + + /* + * Save original pointer for kfree() in case the + * driver is built as a module and can be unloaded. + */ + boardp->orig_sgblkp = sgp; + + /* + * Point 'adv_sgblkp' to the request structures and + * link them together. + */ + sg_cnt--; + sgp[sg_cnt].next_sgblkp = NULL; + for (; sg_cnt > 0; sg_cnt--) { + sgp[sg_cnt - 1].next_sgblkp = &sgp[sg_cnt]; + } + boardp->adv_sgblkp = &sgp[0]; + + ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n"); + warn_code = AdvInitAsc3550Driver(adv_dvc_varp); + err_code = adv_dvc_varp->err_code; + + if (warn_code || err_code) { + ASC_PRINT3( +"AdvInitAsc3550Driver: board %d: error: warn %x, error %x\n", + boardp->id, warn_code, adv_dvc_varp->err_code); + } + } + } + + if (err_code != 0) { release_region(shp->io_port, shp->n_io_port); + if (ASC_WIDE_BOARD(boardp)) { +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + iounmap(boardp->ioremap_addr); +#endif /* version >= v1,3,0 */ + if (boardp->orig_reqp) { + kfree(boardp->orig_reqp); + boardp->orig_reqp = boardp->adv_reqp = NULL; + } + if (boardp->orig_sgblkp) { + kfree(boardp->orig_sgblkp); + boardp->orig_sgblkp = boardp->adv_sgblkp = NULL; + } + } if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } @@ -3576,6 +5091,19 @@ free_dma(shp->dma_channel); } release_region(shp->io_port, shp->n_io_port); + if (ASC_WIDE_BOARD(boardp)) { +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + iounmap(boardp->ioremap_addr); +#endif /* version >= v1,3,0 */ + if (boardp->orig_reqp) { + kfree(boardp->orig_reqp); + boardp->orig_reqp = boardp->adv_reqp = NULL; + } + if (boardp->orig_sgblkp) { + kfree(boardp->orig_sgblkp); + boardp->orig_sgblkp = boardp->adv_sgblkp = NULL; + } + } #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) ASC_ASSERT(boardp->prtbuf != NULL); kfree(boardp->prtbuf); @@ -3600,49 +5128,79 @@ static char info[ASC_INFO_SIZE]; asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_dvc_varp; char *busname; boardp = ASC_BOARDP(shp); - asc_dvc_varp = &boardp->asc_dvc_var; - ASC_DBG(1, "advansys_info: begin\n"); - if (asc_dvc_varp->bus_type & ASC_IS_ISA) { - if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) { - busname = "ISA PnP"; + if (ASC_NARROW_BOARD(boardp)) { + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + ASC_DBG(1, "advansys_info: begin\n"); + if (asc_dvc_varp->bus_type & ASC_IS_ISA) { + if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) { + busname = "ISA PnP"; + } else { + busname = "ISA"; + } + sprintf(info, +"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u, DMA %u", + ASC_VERSION, busname, asc_dvc_varp->max_total_qng, + (unsigned) shp->base, + shp->io_port, shp->n_io_port - 1, + shp->irq, shp->dma_channel); + } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { + if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) + == ASC_IS_PCI_ULTRA) { + busname = "PCI Ultra"; + } else { + busname = "PCI"; + } + sprintf(info, + "AdvanSys SCSI %s: %s %u CDB: IO %X/%X, IRQ %u", + ASC_VERSION, busname, asc_dvc_varp->max_total_qng, + shp->io_port, shp->n_io_port - 1, shp->irq); } else { - busname = "ISA"; + if (asc_dvc_varp->bus_type & ASC_IS_VL) { + busname = "VL"; + } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { + busname = "EISA"; + } else { + busname = "?"; + ASC_PRINT2( + "advansys_info: board %d: unknown bus type %d\n", + boardp->id, asc_dvc_varp->bus_type); + } + sprintf(info, + "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u", + ASC_VERSION, busname, asc_dvc_varp->max_total_qng, + (unsigned) shp->base, shp->io_port - 1, + shp->n_io_port, shp->irq); } - sprintf(info, - "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u, DMA %u", - ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng, - (unsigned) shp->base, shp->io_port, - shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel); - } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { - if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) - == ASC_IS_PCI_ULTRA) { - busname = "PCI Ultra"; - } else { - busname = "PCI"; - } - sprintf(info, - "AdvanSys SCSI %s: %s %u CDB: IO %X-%X, IRQ %u", - ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng, - shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq); - } else { - if (asc_dvc_varp->bus_type & ASC_IS_VL) { - busname = "VL"; - } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { - busname = "EISA"; - } else { - busname = "?"; - ASC_PRINT2( -"advansys_info: board %d: unknown bus type %d\n", - boardp->id, asc_dvc_varp->bus_type); + } else { + /* + * Wide Adapter Information + * + * Memory-mapped I/O is used instead of I/O space to access + * the adapter, but display the I/O Port range. The Memory + * I/O address is displayed through the driver /proc file. + */ + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + if (boardp->bios_signature == 0x55AA) { + sprintf(info, +"AdvanSys SCSI %s: PCI Ultra-Wide: BIOS %X/%X, IO %X/%X, IRQ %u", + ASC_VERSION, + boardp->bios_codeseg << 4, + boardp->bios_codelen > 0 ? + (boardp->bios_codelen << 9) - 1 : 0, + (unsigned) boardp->ioport, ADV_CONDOR_IOLEN - 1, + shp->irq); + } else { + sprintf(info, +"AdvanSys SCSI %s: PCI Ultra-Wide: IO %X/%X, IRQ %u", + ASC_VERSION, + (unsigned) boardp->ioport, + (ADV_CONDOR_IOLEN - 1), + shp->irq); } - sprintf(info, - "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u", - ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng, - (unsigned) shp->base, shp->io_port, - shp->io_port + (shp->n_io_port - 1), shp->irq); } ASC_ASSERT(strlen(info) < ASC_INFO_SIZE); ASC_DBG(1, "advansys_info: end\n"); @@ -3650,10 +5208,10 @@ } /* - * advansys_command() + * advansys_command() - polled I/O entrypoint. * - * Polled-I/O. Apparently host drivers shouldn't return until - * command is finished. + * Apparently host drivers shouldn't return until the command + * is finished. * * Note: This is an old interface that is no longer used by the SCSI * mid-level driver. The new interface, advansys_queuecommand(), @@ -3666,10 +5224,6 @@ ASC_STATS(scp->host, command); scp->SCp.Status = 0; /* Set to a known state */ advansys_queuecommand(scp, advansys_command_done); - /* - * XXX - Can host drivers block here instead of spinning on - * command status? - */ while (scp->SCp.Status == 0) { continue; } @@ -3678,7 +5232,7 @@ } /* - * advansys_queuecommand() + * advansys_queuecommand() - interrupt-driven I/O entrypoint. * * This function always returns 0. Command return status is saved * in the 'scp' result field. @@ -3782,6 +5336,7 @@ struct Scsi_Host *shp; asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_dvc_varp; int flags; int do_scsi_done; int scp_found; @@ -3842,10 +5397,10 @@ do_scsi_done = ASC_TRUE; if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) { /* - * If asc_rmqueue() found the command on the waiting + * If asc_rmqueue() found the command on the waiting * queue, it had not been sent to the device. After * the queue is removed, no other handling is required. - */ + */ ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n", (unsigned) scp); scp_found = ASC_TRUE; @@ -3853,35 +5408,72 @@ ret = SCSI_ABORT_SUCCESS; } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) { /* - * If asc_isqueued() found the command on the active + * If asc_isqueued() found the command on the active * queue, it has been sent to the device. The command - * should be returned through the interrupt handler after - * calling AscAbortSRB(). - */ - asc_dvc_varp = &boardp->asc_dvc_var; - scp->result = HOST_BYTE(DID_ABORT); + * will be returned through the interrupt handler after + * it has been aborted. + */ - sti(); /* Enable interrupts for AscAbortSRB(). */ - ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n", - (unsigned) scp); - switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) { - case ASC_TRUE: - /* asc_isr_callback() will be called */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); - ret = SCSI_ABORT_PENDING; - break; - case ASC_FALSE: - /* Request has apparently already completed. */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n"); - ret = SCSI_ABORT_NOT_RUNNING; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n"); - ret = SCSI_ABORT_ERROR; - break; + if (ASC_NARROW_BOARD(boardp)) { + /* + * Narrow Board + */ + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + scp->result = HOST_BYTE(DID_ABORT); + + sti(); /* Enable interrupts for AscAbortSRB(). */ + ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n", + (unsigned) scp); + switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) { + case ASC_TRUE: + /* asc_isr_callback() will be called */ + ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); + ret = SCSI_ABORT_PENDING; + break; + case ASC_FALSE: + /* Request has apparently already completed. */ + ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n"); + ret = SCSI_ABORT_NOT_RUNNING; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n"); + ret = SCSI_ABORT_ERROR; + break; + } + cli(); + } else { + /* + * Wide Board + */ + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + scp->result = HOST_BYTE(DID_ABORT); + + ASC_DBG1(1, "advansys_abort: before AdvAbortSRB(), scp %x\n", + (unsigned) scp); + switch (AdvAbortSRB(adv_dvc_varp, (ulong) scp)) { + case ASC_TRUE: + /* asc_isr_callback() will be called */ + ASC_DBG(1, "advansys_abort: AdvAbortSRB() TRUE\n"); + ret = SCSI_ABORT_PENDING; + break; + case ASC_FALSE: + /* Request has apparently already completed. */ + ASC_DBG(1, "advansys_abort: AdvAbortSRB() FALSE\n"); + ret = SCSI_ABORT_NOT_RUNNING; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_abort: AdvAbortSRB() ERROR\n"); + ret = SCSI_ABORT_ERROR; + break; + } + /* + * Ensure all requests completed by the microcode have + * been processed by calling AdvISR(). + */ + (void) AdvISR(adv_dvc_varp); } - cli(); /* * The request will either still be on the active queue @@ -3983,6 +5575,7 @@ struct Scsi_Host *shp; asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_dvc_varp; int flags; Scsi_Cmnd *done_scp = NULL, *last_scp = NULL; Scsi_Cmnd *tscp, *new_last_scp; @@ -3991,6 +5584,7 @@ int status; int target; int ret; + int device_reset = ASC_FALSE; /* Save current flags and disable interrupts. */ save_flags(flags); @@ -4056,8 +5650,6 @@ scp->result = HOST_BYTE(DID_ERROR); ret = SCSI_RESET_ERROR; } else { - int device_reset = ASC_FALSE; - do_scsi_done = ASC_TRUE; /* Set reset flag to avoid nested reset or abort requests. */ @@ -4080,83 +5672,166 @@ scp_found = ASC_FALSE; } - /* - * If the suggest reset bus flags are set, reset the bus. - * Otherwise only reset the device. - */ - asc_dvc_varp = &boardp->asc_dvc_var; -#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - if (reset_flags & - (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) { -#endif /* version >= v1.3.89 */ + if (ASC_NARROW_BOARD(boardp)) { /* - * Reset the target's SCSI bus. + * Narrow Board + * + * If the suggest reset bus flags are set, then reset the bus. + * Otherwise only reset the device. */ - ASC_DBG(1, "advansys_reset: before AscResetSB()\n"); - sti(); /* Enable interrupts for AscResetSB(). */ - status = AscResetSB(asc_dvc_varp); - cli(); - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetSB() success\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_reset: AscResetSB() failed\n"); - ret = SCSI_RESET_ERROR; - break; - } - + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - } else { - /* - * Reset the specified device. If the device reset fails, - * then reset the SCSI bus. - */ - - ASC_DBG1(1, "advansys_reset: before AscResetDevice(), target %d\n", - scp->target); - sti(); /* Enable interrupts for AscResetDevice(). */ - status = AscResetDevice(asc_dvc_varp, scp->target); - cli(); - - /* - * If the device has been reset, try to initialize it. - */ - if (status == ASC_TRUE) { - status = asc_init_dev(asc_dvc_varp, scp); - } + if (reset_flags & + (SCSI_RESET_SUGGEST_BUS_RESET | + SCSI_RESET_SUGGEST_HOST_RESET)) { +#endif /* version >= v1.3.89 */ - switch (status) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetDevice() success\n"); - device_reset = ASC_TRUE; - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, -"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n"); + /* + * Reset the target's SCSI bus. + */ + ASC_DBG(1, "advansys_reset: before AscResetSB()\n"); sti(); /* Enable interrupts for AscResetSB(). */ status = AscResetSB(asc_dvc_varp); cli(); switch (status) { case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n"); + ASC_DBG(1, "advansys_reset: AscResetSB() success\n"); ret = SCSI_RESET_SUCCESS; break; case ASC_ERROR: default: - ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n"); + ASC_DBG(1, "advansys_reset: AscResetSB() failed\n"); ret = SCSI_RESET_ERROR; break; } - break; + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + } else { + /* + * Reset the specified device. If the device reset fails, + * then reset the SCSI bus. + */ + + ASC_DBG1(1, + "advansys_reset: before AscResetDevice(), target %d\n", + scp->target); + sti(); /* Enable interrupts for AscResetDevice(). */ + status = AscResetDevice(asc_dvc_varp, scp->target); + cli(); + + /* + * If the device has been reset, try to initialize it. + */ + if (status == ASC_TRUE) { + status = asc_init_dev(asc_dvc_varp, scp); + } + + switch (status) { + case ASC_TRUE: + ASC_DBG(1, "advansys_reset: AscResetDevice() success\n"); + device_reset = ASC_TRUE; + ret = SCSI_RESET_SUCCESS; + break; + case ASC_ERROR: + default: + ASC_DBG(1, +"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n"); + sti(); /* Enable interrupts for AscResetSB(). */ + status = AscResetSB(asc_dvc_varp); + cli(); + switch (status) { + case ASC_TRUE: + ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n"); + ret = SCSI_RESET_SUCCESS; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n"); + ret = SCSI_RESET_ERROR; + break; + } + break; + } + } +#endif /* version >= v1.3.89 */ + } else { + /* + * Wide Board + * + * If the suggest reset bus flags are set, then reset the bus. + * Otherwise only reset the device. + */ + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + if (reset_flags & + (SCSI_RESET_SUGGEST_BUS_RESET | + SCSI_RESET_SUGGEST_HOST_RESET)) { +#endif /* version >= v1.3.89 */ + + /* + * Reset the target's SCSI bus. + */ + ASC_DBG(1, "advansys_reset: before AdvResetSB()\n"); + switch (AdvResetSB(adv_dvc_varp)) { + case ASC_TRUE: + ASC_DBG(1, "advansys_reset: AdvResetSB() success\n"); + ret = SCSI_RESET_SUCCESS; + break; + case ASC_FALSE: + default: + ASC_DBG(1, "advansys_reset: AdvResetSB() failed\n"); + ret = SCSI_RESET_ERROR; + break; + } + /* + * Ensure all requests completed by the microcode have + * been processed by calling AdvISR(). + */ + (void) AdvISR(adv_dvc_varp); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + } else { + /* + * Reset the specified device. If the device reset fails, + * then reset the SCSI bus. + */ + + ASC_DBG1(1, + "advansys_reset: before AdvResetDevice(), target %d\n", + scp->target); + + switch (AdvResetDevice(adv_dvc_varp, scp->target)) { + case ASC_TRUE: + ASC_DBG(1, "advansys_reset: AdvResetDevice() success\n"); + device_reset = ASC_TRUE; + ret = SCSI_RESET_SUCCESS; + break; + case ASC_FALSE: + default: + ASC_DBG(1, +"advansys_reset: AdvResetDevice() failed; Calling AdvResetSB()\n"); + + switch (AdvResetSB(adv_dvc_varp)) { + case ASC_TRUE: + ASC_DBG(1, "advansys_reset: AdvResetSB() TRUE\n"); + ret = SCSI_RESET_SUCCESS; + break; + case ASC_FALSE: + default: + ASC_DBG(1, "advansys_reset: AdvResetSB() ERROR\n"); + ret = SCSI_RESET_ERROR; + break; + } + break; + } + /* + * Ensure all requests completed by the microcode have + * been processed by calling AdvISR(). + */ + (void) AdvISR(adv_dvc_varp); } - } #endif /* version >= v1.3.89 */ + } /* * Because the ASC_HOST_IN_RESET flag causes both @@ -4299,15 +5974,29 @@ advansys_biosparam(Disk *dp, kdev_t dep, int ip[]) #endif /* version >= v1.3.0 */ { + asc_board_t *boardp; + ASC_DBG(1, "advansys_biosparam: begin\n"); ASC_STATS(dp->device->host, biosparam); - if ((ASC_BOARDP(dp->device->host)->asc_dvc_var.dvc_cntl & - ASC_CNTL_BIOS_GT_1GB) && dp->capacity > 0x200000) { - ip[0] = 255; - ip[1] = 63; + boardp = ASC_BOARDP(dp->device->host); + if (ASC_NARROW_BOARD(boardp)) { + if ((boardp->dvc_var.asc_dvc_var.dvc_cntl & + ASC_CNTL_BIOS_GT_1GB) && dp->capacity > 0x200000) { + ip[0] = 255; + ip[1] = 63; + } else { + ip[0] = 64; + ip[1] = 32; + } } else { - ip[0] = 64; - ip[1] = 32; + if ((boardp->dvc_var.adv_dvc_var.bios_ctrl & + BIOS_CTRL_EXTENDED_XLAT) && dp->capacity > 0x200000) { + ip[0] = 255; + ip[1] = 63; + } else { + ip[0] = 64; + ip[1] = 32; + } } ip[2] = dp->capacity / (ip[0] * ip[1]); ASC_DBG(1, "advansys_biosparam: end\n"); @@ -4328,7 +6017,7 @@ * only affects searching for ISA and VL boards. * * If ADVANSYS_DEBUG is defined the driver debug level may - * be set using the 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. + * be set using the 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. * * Examples: * 1. Eliminate I/O port scanning: @@ -4362,15 +6051,15 @@ asc_iopflag = ASC_TRUE; - if (ints[0] > ASC_NUM_BOARD_SUPPORTED) { + if (ints[0] > ASC_NUM_IOPORT_PROBE) { #ifdef ADVANSYS_DEBUG - if ((ints[0] == ASC_NUM_BOARD_SUPPORTED + 1) && - (ints[ASC_NUM_BOARD_SUPPORTED + 1] >> 4 == 0xdeb)) { - asc_dbglvl = ints[ASC_NUM_BOARD_SUPPORTED + 1] & 0xf; + if ((ints[0] == ASC_NUM_IOPORT_PROBE + 1) && + (ints[ASC_NUM_IOPORT_PROBE + 1] >> 4 == 0xdeb)) { + asc_dbglvl = ints[ASC_NUM_IOPORT_PROBE + 1] & 0xf; } else { #endif /* ADVANSYS_DEBUG */ printk("AdvanSys SCSI: only %d I/O ports accepted\n", - ASC_NUM_BOARD_SUPPORTED); + ASC_NUM_IOPORT_PROBE); #ifdef ADVANSYS_DEBUG } #endif /* ADVANSYS_DEBUG */ @@ -4384,7 +6073,7 @@ ASC_DBG(1, "\n"); #endif /* ADVANSYS_DEBUG */ - for (i = 1; i <= ints[0] && i <= ASC_NUM_BOARD_SUPPORTED; i++) { + for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) { asc_ioport[i-1] = ints[i]; ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n", i - 1, asc_ioport[i-1]); @@ -4433,17 +6122,32 @@ cli(); ASC_DBG(1, "advansys_interrupt: begin\n"); + /* * Check for interrupts on all boards. * AscISR() will call asc_isr_callback(). */ for (i = 0; i < asc_board_count; i++) { - ASC_STATS(asc_host[i], check_interrupt); boardp = ASC_BOARDP(asc_host[i]); - while (AscIsIntPending(asc_host[i]->io_port)) { - ASC_STATS(asc_host[i], interrupt); - ASC_DBG(1, "advansys_interrupt: before AscISR()\n"); - AscISR(&boardp->asc_dvc_var); + ASC_DBG2(2, "advansys_interrupt: i %d, boardp %lx\n", + i, (ulong) boardp) + if (ASC_NARROW_BOARD(boardp)) { + /* + * Narrow Board + */ + if (AscIsIntPending(asc_host[i]->io_port)) { + ASC_STATS(asc_host[i], interrupt); + ASC_DBG(1, "advansys_interrupt: before AscISR()\n"); + AscISR(&boardp->dvc_var.asc_dvc_var); + } + } else { + /* + * Wide Board + */ + ASC_DBG(1, "advansys_interrupt: before AdvISR()\n"); + if (AdvISR(&boardp->dvc_var.adv_dvc_var)) { + ASC_STATS(asc_host[i], interrupt); + } } /* @@ -4454,6 +6158,9 @@ * it has completed. */ if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) { + ASC_DBG2(1, "advansys_interrupt: done_scp %lx, last_scp %lx\n", + (ulong) done_scp, (ulong) last_scp); + /* Start any waiting commands for the board. */ if (!ASC_QUEUE_EMPTY(&boardp->waiting)) { ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n"); @@ -4461,8 +6168,12 @@ } /* - * Add to the list of requests that must be completed. - */ + * Add to the list of requests that must be completed. + * + * 'done_scp' will always be NULL on the first iteration + * of this loop. 'last_scp' is set at the same time as + * 'done_scp'. + */ if (done_scp == NULL) { done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL); @@ -4506,6 +6217,7 @@ asc_board_t *boardp; boardp = ASC_BOARDP(shp); + boardp->flags |= ASC_SELECT_QUEUE_DEPTHS; for (device = devicelist; device != NULL; device = device->next) { if (device->host != shp) { continue; @@ -4515,7 +6227,13 @@ * queue depth. */ boardp->device[device->id] = device; - device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id]; + if (ASC_NARROW_BOARD(boardp)) { + device->queue_depth = + boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]; + } else { + device->queue_depth = + boardp->dvc_var.adv_dvc_var.max_dvc_qng; + } ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n", (unsigned) shp, device->id, device->queue_depth); } @@ -4544,7 +6262,9 @@ { Scsi_Cmnd *tscp; + ASC_DBG(2, "asc_scsi_done_list: begin\n"); while (scp != NULL) { + ASC_DBG1(3, "asc_scsi_done_list: scp %x\n", (unsigned) scp); tscp = REQPNEXT(scp); REQPNEXT(scp) = NULL; ASC_STATS(scp->host, done); @@ -4552,6 +6272,7 @@ scp->scsi_done(scp); scp = tscp; } + ASC_DBG(2, "asc_scsi_done_list: done\n"); return; } @@ -4567,28 +6288,29 @@ * target - target of device * lun - lun of device * cmd_len - length of SCSI CDB - * cmnd - buffer for SCSI 8, 10, or 12 byte CDB + * cmnd - buffer for SCSI 8, 10, or 12 byte CDB * use_sg - if non-zero indicates scatter-gather request with use_sg elements * - * if (use_sg == 0) - * request_buffer - buffer address for request - * request_bufflen - length of request buffer - * else - * request_buffer - pointer to scatterlist structure + * if (use_sg == 0) { + * request_buffer - buffer address for request + * request_bufflen - length of request buffer + * } else { + * request_buffer - pointer to scatterlist structure + * } * * sense_buffer - sense command buffer * * result (4 bytes of an int): - * Byte Meaning - * 0 SCSI Status Byte Code - * 1 SCSI One Byte Message Code - * 2 Host Error Code - * 3 Mid-Level Error Code + * Byte Meaning + * 0 SCSI Status Byte Code + * 1 SCSI One Byte Message Code + * 2 Host Error Code + * 3 Mid-Level Error Code * * host driver fields: - * SCp - Scsi_Pointer used for command processing status - * scsi_done - used to save caller's done function - * host_scribble - used for pointer to another Scsi_Cmnd + * SCp - Scsi_Pointer used for command processing status + * scsi_done - used to save caller's done function + * host_scribble - used for pointer to another Scsi_Cmnd * * If this function returns ASC_NOERROR or ASC_ERROR the request * has been enqueued on the board's 'done' queue and must be @@ -4602,6 +6324,8 @@ { asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; + ADV_DVC_VAR *adv_dvc_varp; + ADV_SCSI_REQ_Q *adv_scsiqp; Scsi_Device *device; int ret; @@ -4610,22 +6334,199 @@ (unsigned) scp, (unsigned) scp->scsi_done); boardp = ASC_BOARDP(scp->host); - asc_dvc_varp = &boardp->asc_dvc_var; device = boardp->device[scp->target]; - /* - * If this is the first command, then initialize the device. If - * no device is found set 'DID_BAD_TARGET' and return. - */ - if ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(scp->target)) == 0) { - if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) { - scp->result = HOST_BYTE(DID_BAD_TARGET); + if (ASC_NARROW_BOARD(boardp)) { + /* + * Build and execute Narrow Board request. + */ + + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + + /* + * Narrow Board - Asc Library requires special device initialization. + * + * If this is the first command, then initialize the device. If + * no device is found set 'DID_BAD_TARGET' and return. + */ + if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0) { + if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) { + scp->result = HOST_BYTE(DID_BAD_TARGET); + asc_enqueue(&boardp->done, scp, ASC_BACK); + return ASC_ERROR; + } + boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target); + } + + /* + * Build Asc Library request structure using the + * global structures 'asc_scsi_req' and 'asc_sg_head'. + * + * asc_build_req() can not return ASC_BUSY. + */ + if (asc_build_req(boardp, scp) == ASC_ERROR) { + ASC_STATS(scp->host, build_error); + return ASC_ERROR; + } + + /* + * Execute the command. If there is no error, add the command + * to the active queue. + */ + switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) { + case ASC_NOERROR: + ASC_STATS(scp->host, exe_noerror); + /* + * Increment monotonically increasing per device successful + * request counter. Wrapping doesn't matter. + */ + boardp->reqcnt[scp->target]++; + +#if ASC_QUEUE_FLOW_CONTROL + /* + * Conditionally increment the device queue depth. + * + * If no error occurred and there have been 100 consecutive + * successful requests and the current queue depth is less + * than the maximum queue depth, then increment the current + * queue depth. + */ + if (boardp->nerrcnt[scp->target]++ > 100) { + boardp->nerrcnt[scp->target] = 0; + if (device != NULL && + (device->queue_curr_depth < device->queue_depth) && + (!(boardp->queue_full & + ADV_TID_TO_TIDMASK(scp->target)) || + (boardp->queue_full_cnt[scp->target] > + device->queue_curr_depth))) { + device->queue_curr_depth++; + } + } +#endif /* ASC_QUEUE_FLOW_CONTROL */ + asc_enqueue(&boardp->active, scp, ASC_BACK); + ASC_DBG(1, + "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); + break; + case ASC_BUSY: + /* Caller must enqueue request and retry later. */ + ASC_STATS(scp->host, exe_busy); +#if ASC_QUEUE_FLOW_CONTROL + /* + * Clear consecutive no error counter and if possible decrement + * queue depth. + */ + boardp->nerrcnt[scp->target] = 0; + if (device != NULL && device->queue_curr_depth > 1) { + device->queue_curr_depth--; + } +#endif /* ASC_QUEUE_FLOW_CONTROL */ + break; + case ASC_ERROR: + ASC_PRINT2( +"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n", + boardp->id, asc_dvc_varp->err_code); + ASC_STATS(scp->host, exe_error); +#if ASC_QUEUE_FLOW_CONTROL + /* Clear consecutive no error counter. */ + boardp->nerrcnt[scp->target] = 0; +#endif /* ASC_QUEUE_FLOW_CONTROL */ + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + break; + default: + ASC_PRINT2( +"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n", + boardp->id, asc_dvc_varp->err_code); + ASC_STATS(scp->host, exe_unknown); +#if ASC_QUEUE_FLOW_CONTROL + /* Clear consecutive no error counter. */ + boardp->nerrcnt[scp->target] = 0; +#endif /* ASC_QUEUE_FLOW_CONTROL */ + scp->result = HOST_BYTE(DID_ERROR); asc_enqueue(&boardp->done, scp, ASC_BACK); + break; + } + } else { + /* + * Build and execute Wide Board request. + */ + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + + /* + * Build and get a pointer to an Adv Library request structure. + * + * If the request is successfully built then send it below, + * otherwise return with an error. + */ + switch (adv_build_req(boardp, scp, &adv_scsiqp)) { + case ASC_NOERROR: + ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n"); + break; + case ASC_BUSY: + ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n"); + return ASC_BUSY; + case ASC_ERROR: + default: + ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n"); + ASC_STATS(scp->host, build_error); return ASC_ERROR; } - boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target); + + /* + * Execute the command. If there is no error, add the command + * to the active queue. + */ + switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) { + case ASC_NOERROR: + ASC_STATS(scp->host, exe_noerror); + /* + * Increment monotonically increasing per device successful + * request counter. Wrapping doesn't matter. + */ + boardp->reqcnt[scp->target]++; + asc_enqueue(&boardp->active, scp, ASC_BACK); + ASC_DBG(1, + "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n"); + break; + case ASC_BUSY: + /* Caller must enqueue request and retry later. */ + ASC_STATS(scp->host, exe_busy); + break; + case ASC_ERROR: + ASC_PRINT2( +"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code %x\n", + boardp->id, adv_dvc_varp->err_code); + ASC_STATS(scp->host, exe_error); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + break; + default: + ASC_PRINT2( +"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code %x\n", + boardp->id, adv_dvc_varp->err_code); + ASC_STATS(scp->host, exe_unknown); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + break; + } } + ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + return ret; +} + +/* + * Build a request structure for the Asc Library (Narrow Board). + * + * The global structures 'asc_scsi_q' and 'asc_sg_head' are + * used to build the request. + * + * If an error occurs, then return ASC_ERROR. + */ +STATIC int +asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp) +{ /* * Mutually exclusive access is required to 'asc_scsi_q' and * 'asc_sg_head' until after the request is started. @@ -4640,6 +6541,10 @@ /* * Build the ASC_SCSI_Q request. */ + ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN); + if (scp->cmd_len > ASC_MAX_CDB_LEN) { + scp->cmd_len = ASC_MAX_CDB_LEN; + } asc_scsi_q.cdbptr = &scp->cmnd[0]; asc_scsi_q.q2.cdb_len = scp->cmd_len; asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target); @@ -4663,7 +6568,7 @@ * started request. * */ - if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 0) && + if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->target] > 0) && (boardp->reqcnt[scp->target] % 255) == 0) { asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED; } else { @@ -4693,12 +6598,12 @@ /* * CDB scatter-gather request list. */ - int sgcnt; - struct scatterlist *slp; + int sgcnt; + struct scatterlist *slp; if (scp->use_sg > scp->host->sg_tablesize) { ASC_PRINT3( -"asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n", +"asc_build_req: board %d: use_sg %d > sg_tablesize %d\n", boardp->id, scp->use_sg, scp->host->sg_tablesize); scp->result = HOST_BYTE(DID_ERROR); asc_enqueue(&boardp->done, scp, ASC_BACK); @@ -4708,8 +6613,8 @@ ASC_STATS(scp->host, sg_cnt); /* - * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q - * to point to it. + * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q + * structure to point to it. */ memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD)); @@ -4735,91 +6640,262 @@ } } - ASC_DBG_PRT_SCSI_Q(2, &asc_scsi_q); + ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q); ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); - /* - * Execute the command. If there is no error, add the command - * to the active queue. - */ - switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) { - case ASC_NOERROR: - ASC_STATS(scp->host, asc_noerror); - /* - * Increment monotonically increasing per device successful - * request counter. Wrapping doesn't matter. - */ - boardp->reqcnt[scp->target]++; + return ASC_NOERROR; +} -#if ASC_QUEUE_FLOW_CONTROL - /* - * Conditionally increment the device queue depth. - * - * If no error occurred and there have been 100 consecutive - * successfull requests and the current queue depth is less - * than the maximum queue depth, then increment the current - * queue depth. +/* + * Build a request structure for the Adv Library (Wide Board). + * + * If an adv_req_t can not be allocated to issue the request, + * then return ASC_BUSY. If an error occurs, then return ASC_ERROR. + */ +STATIC int +adv_build_req(asc_board_t *boardp, Scsi_Cmnd *scp, + ADV_SCSI_REQ_Q **adv_scsiqpp) +{ + adv_req_t *reqp; + ADV_SCSI_REQ_Q *scsiqp; + int i; + + /* + * Allocate an adv_req_t structure from the board to execute + * the command. + */ + if (boardp->adv_reqp == NULL) { + ASC_DBG(1, "adv_build_req: no free adv_req_t\n"); + ASC_STATS(scp->host, adv_build_noreq); + return ASC_BUSY; + } else { + reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp->next_reqp; + reqp->next_reqp = NULL; + } + + /* + * Get 4-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers. + */ + scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q); + memset(scsiqp, 0, sizeof(ADV_SCSI_REQ_Q)); + + /* + * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure. + */ + scsiqp->srb_ptr = (ulong) reqp; + + /* + * Set the adv_req_t 'cmndp' to point to the Scsi_Cmnd structure. + */ + reqp->cmndp = scp; + + /* + * Build the ADV_SCSI_REQ_Q request. + */ + + /* + * Set CDB length and copy it to the request structure. + */ + ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN); + if (scp->cmd_len > ASC_MAX_CDB_LEN) { + scp->cmd_len = ASC_MAX_CDB_LEN; + } + scsiqp->cdb_len = scp->cmd_len; + for (i = 0; i < scp->cmd_len; i++) { + scsiqp->cdb[i] = scp->cmnd[i]; + } + + scsiqp->target_id = scp->target; + scsiqp->target_lun = scp->lun; + + scsiqp->vsense_addr = (ulong) &scp->sense_buffer[0]; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + scsiqp->sense_addr = (ulong) &scp->sense_buffer[0]; +#else /* version >= v2.0.0 */ + scsiqp->sense_addr = virt_to_bus(&scp->sense_buffer[0]); +#endif /* version >= v2.0.0 */ + scsiqp->sense_len = sizeof(scp->sense_buffer); + + /* + * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather + * buffer command. + */ + scsiqp->data_cnt = scp->request_bufflen; + scsiqp->vdata_addr = (ulong) scp->request_buffer; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + scsiqp->data_addr = (ulong) scp->request_buffer; +#else /* version >= v2.0.0 */ + scsiqp->data_addr = virt_to_bus(scp->request_buffer); +#endif /* version >= v2.0.0 */ + + if (scp->use_sg == 0) { + /* + * CDB request of single contiguous buffer. */ - if (boardp->nerrcnt[scp->target]++ > 100) { - boardp->nerrcnt[scp->target] = 0; - if ((device->queue_curr_depth < device->queue_depth) && - (!(boardp->queue_full & ASC_TIX_TO_TARGET_ID(scp->target)) || - (boardp->queue_full_cnt[scp->target] > - device->queue_curr_depth))) { - device->queue_curr_depth++; - } + reqp->sgblkp = NULL; + scsiqp->sg_list_ptr = NULL; + ASC_STATS(scp->host, cont_cnt); + ASC_STATS_ADD(scp->host, cont_xfer, + ASC_CEILING(scp->request_bufflen, 512)); + } else { + /* + * CDB scatter-gather request list. + */ + if (scp->use_sg > ADV_MAX_SG_LIST) { + ASC_PRINT3( +"adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n", + boardp->id, scp->use_sg, scp->host->sg_tablesize); + scp->result = HOST_BYTE(DID_ERROR); + asc_enqueue(&boardp->done, scp, ASC_BACK); + + /* + * Free the 'adv_req_t' structure by adding it back to the + * board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + + return ASC_ERROR; } -#endif /* ASC_QUEUE_FLOW_CONTROL */ - asc_enqueue(&boardp->active, scp, ASC_BACK); - ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); - break; - case ASC_BUSY: - /* Caller must enqueue request and retry later. */ - ASC_STATS(scp->host, asc_busy); -#if ASC_QUEUE_FLOW_CONTROL + /* - * Clear consecutive no error counter and if possbile decrement - * queue depth. + * Allocate an 'adv_sgblk_t' structure from the board to + * execute the command. */ - boardp->nerrcnt[scp->target] = 0; - if (device->queue_curr_depth > 1) { - device->queue_curr_depth--; + if (boardp->adv_sgblkp == NULL) { + ASC_DBG(1, "adv_build_req: no free adv_sgblk_t\n"); + ASC_STATS(scp->host, adv_build_nosg); + /* + * Free the 'adv_req_t' structure by adding it back to the + * board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + return ASC_BUSY; + } else { + reqp->sgblkp = boardp->adv_sgblkp; + boardp->adv_sgblkp = reqp->sgblkp->next_sgblkp; + reqp->sgblkp->next_sgblkp = NULL; } -#endif /* ASC_QUEUE_FLOW_CONTROL */ - break; - case ASC_ERROR: - ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n", - boardp->id, asc_dvc_varp->err_code); - ASC_STATS(scp->host, asc_error); -#if ASC_QUEUE_FLOW_CONTROL - /* Clear consecutive no error counter. */ - boardp->nerrcnt[scp->target] = 0; -#endif /* ASC_QUEUE_FLOW_CONTROL */ - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - break; - default: - ASC_PRINT2( -"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n", - boardp->id, asc_dvc_varp->err_code); - ASC_STATS(scp->host, asc_unknown); -#if ASC_QUEUE_FLOW_CONTROL - /* Clear consecutive no error counter. */ - boardp->nerrcnt[scp->target] = 0; -#endif /* ASC_QUEUE_FLOW_CONTROL */ - scp->result = HOST_BYTE(DID_ERROR); - asc_enqueue(&boardp->done, scp, ASC_BACK); - break; + + /* + * Build scatter-gather list. + */ + scsiqp->sg_list_ptr = (ADV_SG_BLOCK *) + ADV_DWALIGN(&reqp->sgblkp->sg_block[0]); + + memset(scsiqp->sg_list_ptr, 0, sizeof(ADV_SG_BLOCK) * + (ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING)); + + if (adv_get_sglist(&boardp->dvc_var.adv_dvc_var, scsiqp, scp) == + ADV_ERROR) { + + /* + * Free the adv_sgblk_t structure, if any, by adding it back + * to the board free list. + */ + ASC_ASSERT(reqp->sgblkp != NULL); + reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp; + boardp->adv_sgblkp = reqp->sgblkp; + + /* + * Free the adv_req_t structure by adding it back to the + * board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + + return ADV_ERROR; + } + + ASC_STATS(scp->host, sg_cnt); + ASC_STATS_ADD(scp->host, sg_elem, scp->use_sg); } - ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - return ret; + ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); + ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); + + *adv_scsiqpp = scsiqp; + + return ASC_NOERROR; +} + +/* + * Build scatter-gather list for Adv Library (Wide Board). + * + * Return: + * ADV_SUCCESS(1) - SG List successfully created + * ADV_ERROR(-1) - SG List creation failed + */ +STATIC int +adv_get_sglist(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp, + Scsi_Cmnd *scp) +{ + ADV_SG_BLOCK *sg_block; /* virtual address of a SG */ + ulong sg_block_next_addr; /* block and its next */ + ulong sg_block_physical_addr; + int sg_block_index, i; /* how many SG entries */ + struct scatterlist *slp; + int sg_elem_cnt; + + slp = (struct scatterlist *) scp->request_buffer; + sg_elem_cnt = scp->use_sg; + + sg_block = scsiqp->sg_list_ptr; + sg_block_next_addr = (ulong) sg_block; /* allow math operation */ + sg_block_physical_addr = +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + (ulong) scsiqp->sg_list_ptr; +#else /* version >= v2.0.0 */ + virt_to_bus(scsiqp->sg_list_ptr); +#endif /* version >= v2.0.0 */ + ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) == + sg_block_physical_addr); + scsiqp->sg_real_addr = sg_block_physical_addr; + + sg_block_index = 0; + do + { + sg_block->first_entry_no = sg_block_index; + for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) + { + sg_block->sg_list[i].sg_addr = +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + (ulong) slp->address; +#else /* version >= v2.0.0 */ + virt_to_bus(slp->address); +#endif /* version >= v2.0.0 */ + sg_block->sg_list[i].sg_count = slp->length; + ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); + + if (--sg_elem_cnt == 0) + { /* last entry, get out */ + scsiqp->sg_entry_cnt = sg_block_index + i + 1; + sg_block->last_entry_no = sg_block_index + i; + sg_block->sg_ptr = 0L; /* next link = NULL */ + return ADV_SUCCESS; + } + slp++; + } + sg_block_next_addr += sizeof(ADV_SG_BLOCK); + sg_block_physical_addr += sizeof(ADV_SG_BLOCK); + ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) == + sg_block_physical_addr); + + sg_block_index += NO_OF_SG_PER_BLOCK; + sg_block->sg_ptr = (ADV_SG_BLOCK *) sg_block_physical_addr; + sg_block->last_entry_no = sg_block_index - 1; + sg_block = (ADV_SG_BLOCK *) sg_block_next_addr; /* virtual addr */ + } + while (1); + /* NOTREACHED */ } /* * asc_isr_callback() - Second Level Interrupt Handler called by AscISR(). + * + * Interrupt callback function for the Narrow SCSI Asc Library. */ STATIC void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) @@ -4827,12 +6903,13 @@ asc_board_t *boardp; Scsi_Cmnd *scp; struct Scsi_Host *shp; + int underrun = ASC_FALSE; int i; ASC_ASSERT(interrupts_enabled() == ASC_FALSE); ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n", (unsigned) asc_dvc_varp, (unsigned) qdonep); - ASC_DBG_PRT_QDONE_INFO(2, qdonep); + ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); /* * Get the Scsi_Cmnd structure and Scsi_Host structure for the @@ -4840,12 +6917,12 @@ */ scp = (Scsi_Cmnd *) qdonep->d2.srb_ptr; ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp); - ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); if (scp == NULL) { ASC_PRINT("asc_isr_callback: scp is NULL\n"); return; } + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); /* * If the request's host pointer is not valid, display a @@ -4879,6 +6956,16 @@ } /* + * Check for an underrun condition. + */ + if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 && + qdonep->remain_bytes <= scp->request_bufflen != 0) { + ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n", + (unsigned) qdonep->remain_bytes); + underrun = ASC_TRUE; + } + + /* * 'qdonep' contains the command's ending status. */ switch (qdonep->d3.done_stat) { @@ -4893,6 +6980,13 @@ scp->result = HOST_BYTE(DID_ERROR); break; } + /* + * If there was an underrun without any other error, + * set DID_ERROR to indicate the underrun error. + */ + if (scp->result == 0 && underrun == ASC_TRUE) { + scp->result = HOST_BYTE(DID_UNDERRUN); + } break; case QD_WITH_ERROR: @@ -4955,113 +7049,318 @@ } /* - * asc_init_dev() + * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR(). * - * Perform one-time initialization of a device. + * Callback function for the Wide SCSI Adv Library. */ -STATIC int -asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp) +STATIC void +adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) { - asc_board_t *boardp; - ASC_SCSI_REQ_Q *scsireqq; - ASC_CAP_INFO *cap_info; - ASC_SCSI_INQUIRY *inquiry; - int found; - ASC_SCSI_BIT_ID_TYPE save_use_tagged_qng; - ASC_SCSI_BIT_ID_TYPE save_can_tagged_qng; - int ret; -#ifdef ADVANSYS_DEBUG - ASC_SCSI_BIT_ID_TYPE tidmask; /* target id bit mask: 1 - 128 */ -#endif /* ADVANSYS_DEBUG */ - - ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target); - - /* The host's target id is set in init_tidmask during initialization. */ - ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target); + asc_board_t *boardp; + adv_req_t *reqp; + Scsi_Cmnd *scp; + struct Scsi_Host *shp; + int underrun = ASC_FALSE; + int i; - boardp = ASC_BOARDP(scp->host); + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %x, scsiqp %x\n", + (unsigned) adv_dvc_varp, (unsigned) scsiqp); + ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); - /* Set-up AscInitPollTarget() arguments. */ - scsireqq = &boardp->scsireqq; - memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q)); - cap_info = &boardp->cap_info; - memset(cap_info, 0, sizeof(ASC_CAP_INFO)); - inquiry = &boardp->inquiry; - memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY)); + /* + * Get the adv_req_t structure for the command that has been + * completed. The adv_req_t structure actually contains the + * completed ADV_SCSI_REQ_Q structure. + */ + reqp = (adv_req_t *) scsiqp->srb_ptr; + ASC_DBG1(1, "adv_isr_callback: reqp %x\n", (unsigned) reqp); + if (reqp == NULL) { + ASC_PRINT("adv_isr_callback: reqp is NULL\n"); + return; + } /* - * XXX - AscInitPollBegin() re-initializes these fields to - * zero. 'Or' in the new values and restore them before calling - * AscInitPollEnd(). Normally all targets are initialized within - * a call to AscInitPollBegin() and AscInitPollEnd(). + * Get the Scsi_Cmnd structure and Scsi_Host structure for the + * command that has been completed. + * + * Note: The adv_req_t request structure and adv_sgblk_t structure, + * if any, * dropped, because a board structure pointer can not be + * determined. */ - save_use_tagged_qng = asc_dvc_varp->use_tagged_qng; - save_can_tagged_qng = asc_dvc_varp->cfg->can_tagged_qng; - - ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n"); - if (AscInitPollBegin(asc_dvc_varp)) { - ASC_PRINT1("asc_init_dev: board %d: AscInitPollBegin() failed\n", - boardp->id); - return ASC_FALSE; + scp = reqp->cmndp; + ASC_DBG1(1, "adv_isr_callback: scp %x\n", (unsigned) scp); + if (scp == NULL) { + ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n"); + return; } + ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); - scsireqq->sense_ptr = &scsireqq->sense[0]; - scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN; - scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target); - scsireqq->r1.target_lun = 0; - scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0); - - found = ASC_FALSE; - ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n"); - switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry, - cap_info)) { - case ASC_TRUE: - found = ASC_TRUE; -#ifdef ADVANSYS_DEBUG - tidmask = ASC_TIX_TO_TARGET_ID(scp->target); - ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n", - cap_info->lba, cap_info->blk_size); - ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n", - inquiry->byte0.peri_dvc_type); - if (asc_dvc_varp->use_tagged_qng & tidmask) { - ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n", - asc_dvc_varp->max_dvc_qng[scp->target]); - } else { - ASC_DBG(1, "asc_init_dev: command queuing disabled\n"); - } - if (asc_dvc_varp->init_sdtr & tidmask) { - ASC_DBG(1, "asc_init_dev: synchronous transfers enabled\n"); - } else { - ASC_DBG(1, "asc_init_dev: synchronous transfers disabled\n"); - } - /* Set bit means fix disabled. */ - if (asc_dvc_varp->pci_fix_asyn_xfer & tidmask) { - ASC_DBG(1, "asc_init_dev: synchronous transfer fix disabled\n"); - } else { - ASC_DBG(1, "asc_init_dev: synchronous transfer fix enabled\n"); + /* + * If the request's host pointer is not valid, display a message + * and return. + */ + shp = scp->host; + for (i = 0; i < asc_board_count; i++) { + if (asc_host[i] == shp) { + break; } -#endif /* ADVANSYS_DEBUG */ - break; - case ASC_FALSE: - ASC_DBG(1, "asc_init_dev: no device found\n"); - break; - case ASC_ERROR: - ASC_PRINT1("asc_init_dev: board %d: AscInitPollTarget() ASC_ERROR\n", - boardp->id); - break; - default: - ASC_PRINT2( -"asc_init_dev: board %d: AscInitPollTarget() unknown ret %d\n", - boardp->id, ret); - break; + } + /* + * Note: If the host structure is not found, the adv_req_t request + * structure and adv_sgblk_t structure, if any, is dropped. + */ + if (i == asc_board_count) { + ASC_PRINT2("adv_isr_callback: scp %x has bad host pointer, host %x\n", + (unsigned) scp, (unsigned) shp); + return; } - /* XXX - 'Or' in original tag bits. */ - asc_dvc_varp->use_tagged_qng |= save_use_tagged_qng; - asc_dvc_varp->cfg->can_tagged_qng |= save_can_tagged_qng; - - ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n"); - AscInitPollEnd(asc_dvc_varp); + ASC_STATS(shp, callback); + ASC_DBG1(1, "adv_isr_callback: shp %x\n", (unsigned) shp); + + /* + * If the request isn't found on the active queue, it may have been + * removed to handle a reset or abort request. Display a message and + * return. + * + * Note: Because the structure may still be in use don't attempt + * to free the adv_req_t and adv_sgblk_t, if any, structures. + */ + boardp = ASC_BOARDP(shp); + if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { + ASC_PRINT2("adv_isr_callback: board %d: scp %x not on active queue\n", + boardp->id, (unsigned) scp); + return; + } + + /* + * Check for an underrun condition. + */ + if (scp->request_bufflen != 0 && scsiqp->data_cnt != 0) { + ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n", + scsiqp->data_cnt); + underrun = ASC_TRUE; + } + + /* + * 'done_status' contains the command's ending status. + */ + switch (scsiqp->done_status) { + case QD_NO_ERROR: + ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n"); + switch (scsiqp->host_status) { + case QHSTA_NO_ERROR: + scp->result = 0; + break; + default: + /* QHSTA error occurred. */ + ASC_DBG1(2, "adv_isr_callback: host_status %x\n", + scsiqp->host_status); + scp->result = HOST_BYTE(DID_ERROR); + break; + } + /* + * If there was an underrun without any other error, + * set DID_ERROR to indicate the underrun error. + */ + if (scp->result == 0 && underrun == ASC_TRUE) { + scp->result = HOST_BYTE(DID_UNDERRUN); + } + break; + + case QD_WITH_ERROR: + ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n"); + switch (scsiqp->host_status) { + case QHSTA_NO_ERROR: + if (scsiqp->scsi_status == SS_CHK_CONDITION) { + ASC_DBG(2, "adv_isr_callback: SS_CHK_CONDITION\n"); + ASC_DBG_PRT_SENSE(2, scp->sense_buffer, + sizeof(scp->sense_buffer)); + /* + * Note: The 'status_byte()' macro used by target drivers + * defined in scsi.h shifts the status byte returned by + * host drivers right by 1 bit. This is why target drivers + * also use right shifted status byte definitions. For + * instance target drivers use CHECK_CONDITION, defined to + * 0x1, instead of the SCSI defined check condition value + * of 0x2. Host drivers are supposed to return the status + * byte as it is defined by SCSI. + */ + scp->result = DRIVER_BYTE(DRIVER_SENSE) | + STATUS_BYTE(scsiqp->scsi_status); + } else { + scp->result = STATUS_BYTE(scsiqp->scsi_status); + } + break; + + default: + /* Some other QHSTA error occurred. */ + ASC_DBG1(2, "adv_isr_callback: host_status %x\n", + scsiqp->host_status); + scp->result = HOST_BYTE(DID_BAD_TARGET); + break; + } + break; + + case QD_ABORTED_BY_HOST: + ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n"); + scp->result = HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status); + break; + + default: + ASC_PRINT1("adv_isr_callback: done_status %x\n", scsiqp->done_status); + scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status); + break; + } + + /* + * If the 'init_tidmask' bit isn't already set for the target and the + * current request did not finish with a Selection Timeout, then set + * the bit for the target to indicate that a device is present. + */ + if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0 && + scsiqp->done_status == QD_NO_ERROR && + scsiqp->host_status == QHSTA_NO_ERROR) { + boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target); + } + + /* + * Because interrupts may be enabled by the 'Scsi_Cmnd' done + * function, add the command to the end of the board's done queue. + * The done function for the command will be called from + * advansys_interrupt(). + */ + asc_enqueue(&boardp->done, scp, ASC_BACK); + + /* + * Free the adv_sgblk_t structure, if any, by adding it back + * to the board free list. + */ + if (reqp->sgblkp != NULL) { + reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp; + boardp->adv_sgblkp = reqp->sgblkp; + } + + /* + * Free the adv_req_t structure used with the command by adding + * it back to the board free list. + */ + reqp->next_reqp = boardp->adv_reqp; + boardp->adv_reqp = reqp; + + ASC_DBG(1, "adv_isr_callback: done\n"); + + return; +} + +/* + * asc_init_dev() - Narrow Board initialization function. + * + * Perform one-time initialization of a device for Asc Library + */ +STATIC int +asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp) +{ + asc_board_t *boardp; + ASC_SCSI_REQ_Q *scsireqq; + ASC_CAP_INFO *cap_info; + ASC_SCSI_INQUIRY *inquiry; + int found; + ASC_SCSI_BIT_ID_TYPE save_use_tagged_qng; + ASC_SCSI_BIT_ID_TYPE save_can_tagged_qng; + int ret; +#ifdef ADVANSYS_DEBUG + ASC_SCSI_BIT_ID_TYPE tidmask; /* target id bit mask: 1 - 128 */ +#endif /* ADVANSYS_DEBUG */ + + ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target); + + /* The host's target id is set in init_tidmask during initialization. */ + ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target); + + boardp = ASC_BOARDP(scp->host); + + /* Set-up AscInitPollTarget() arguments. */ + scsireqq = &boardp->scsireqq; + memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q)); + cap_info = &boardp->cap_info; + memset(cap_info, 0, sizeof(ASC_CAP_INFO)); + inquiry = &boardp->inquiry; + memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY)); + + /* + * AscInitPollBegin() re-initializes these bitmask fields to zero. + * Save the current bitmask value and 'or' them back in after calling + * AscInitPollEnd() below.. + */ + save_use_tagged_qng = asc_dvc_varp->use_tagged_qng; + save_can_tagged_qng = asc_dvc_varp->cfg->can_tagged_qng; + + ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n"); + if (AscInitPollBegin(asc_dvc_varp)) { + ASC_PRINT1("asc_init_dev: board %d: AscInitPollBegin() failed\n", + boardp->id); + return ASC_FALSE; + } + + scsireqq->sense_ptr = &scsireqq->sense[0]; + scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN; + scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target); + scsireqq->r1.target_lun = 0; + scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0); + + found = ASC_FALSE; + ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n"); + switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry, + cap_info)) { + case ASC_TRUE: + found = ASC_TRUE; +#ifdef ADVANSYS_DEBUG + tidmask = ADV_TID_TO_TIDMASK(scp->target); + ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n", + cap_info->lba, cap_info->blk_size); + ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n", + inquiry->byte0.peri_dvc_type); + if (asc_dvc_varp->use_tagged_qng & tidmask) { + ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n", + asc_dvc_varp->max_dvc_qng[scp->target]); + } else { + ASC_DBG(1, "asc_init_dev: command queuing disabled\n"); + } + if (asc_dvc_varp->init_sdtr & tidmask) { + ASC_DBG(1, "asc_init_dev: synchronous transfers enabled\n"); + } else { + ASC_DBG(1, "asc_init_dev: synchronous transfers disabled\n"); + } + /* Set bit means fix disabled. */ + if (asc_dvc_varp->pci_fix_asyn_xfer & tidmask) { + ASC_DBG(1, "asc_init_dev: synchronous transfer fix disabled\n"); + } else { + ASC_DBG(1, "asc_init_dev: synchronous transfer fix enabled\n"); + } +#endif /* ADVANSYS_DEBUG */ + break; + case ASC_FALSE: + ASC_DBG(1, "asc_init_dev: no device found\n"); + break; + case ASC_ERROR: + ASC_PRINT1("asc_init_dev: board %d: AscInitPollTarget() ASC_ERROR\n", + boardp->id); + break; + default: + ASC_PRINT2( +"asc_init_dev: board %d: AscInitPollTarget() unknown ret %d\n", + boardp->id, ret); + break; + } + + /* Restore previously set bits in the bitmask fields. */ + asc_dvc_varp->use_tagged_qng |= save_use_tagged_qng; + asc_dvc_varp->cfg->can_tagged_qng |= save_can_tagged_qng; + + ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n"); + AscInitPollEnd(asc_dvc_varp); ASC_DBG1(1, "asc_init_dev: found %d\n", found); @@ -5169,7 +7468,8 @@ if ((vendorid == ASC_PCI_VENDORID) && ((deviceid == ASC_PCI_DEVICE_ID_1100) || (deviceid == ASC_PCI_DEVICE_ID_1200) || - (deviceid == ASC_PCI_DEVICE_ID_1300))) { + (deviceid == ASC_PCI_DEVICE_ID_1300) || + (deviceid == ASC_PCI_DEVICE_ID_2300))) { pciDevice->slotFound = lslot; ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n"); return PCI_DEVICE_FOUND; @@ -5314,74 +7614,8 @@ ) { uchar tmp; - ulong address; - ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; - uchar t2CFA, t2CF8; - ulong t1CF8, t1CFC; - - ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type); - - /* - * Check type of configuration mechanism. - */ - if (pciData->type == 2) { - /* - * Save registers to be restored later. - */ - t2CFA = inp(0xCFA); /* save PCI bus register */ - t2CF8 = inp(0xCF8); /* save config space enable register */ - - /* - * Write the bus and enable registers. - */ - /* set for type 1 cycle, if needed */ - outp(0xCFA, pciData->bus); - /* set the function number */ - outp(0xCF8, 0x10 | (pciData->func << 1)); - - /* - * Read configuration space type 2 locations. - */ - tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset)); - - /* - * Restore registers. - */ - outp(0xCF8, t2CF8); /* restore the enable register */ - outp(0xCFA, t2CFA); /* restore PCI bus register */ - } else { - /* - * Type 1 or 3 configuration mechanism. - * - * Save CONFIG_ADDRESS and CONFIG_DATA register values. - */ - t1CF8 = inpl(0xCF8); - t1CFC = inpl(0xCFC); - - /* - * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, - * reg = <7:2> - */ - address = (ulong) ((lbus << 16) | (lslot << 11) | - (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); - - /* - * Write out address to CONFIG_ADDRESS. - */ - outpl(0xCF8, address); - - /* - * Read in word from CONFIG_DATA. - */ - tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF); - /* - * Restore registers. - */ - outpl(0xCF8, t1CF8); - outpl(0xCFC, t1CFC); - } - ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp); + pcibios_read_config_byte(pciData->bus, pciData->slot * 8 + pciData->func, pciData->offset, &tmp); return tmp; } @@ -5483,13 +7717,13 @@ { int tid; - ASC_DBG3(2, "asc_enqueue: ascq %x, reqp %x, flag %d\n", + ASC_DBG3(3, "asc_enqueue: ascq %x, reqp %x, flag %d\n", (unsigned) ascq, (unsigned) reqp, flag); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK); tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID); + ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); if (flag == ASC_FRONT) { REQPNEXT(reqp) = ascq->q_first[tid]; ascq->q_first[tid] = reqp; @@ -5509,19 +7743,19 @@ } } /* The queue has at least one entry, set its bit. */ - ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid); + ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid); #ifdef ADVANSYS_STATS /* Maintain request queue statistics. */ ascq->q_tot_cnt[tid]++; ascq->q_cur_cnt[tid]++; if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) { ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid]; - ASC_DBG2(1, "asc_enqueue: new q_max_cnt[%d] %d\n", + ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n", tid, ascq->q_max_cnt[tid]); } REQPTIME(reqp) = REQTIMESTAMP(); #endif /* ADVANSYS_STATS */ - ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp); + ASC_DBG1(3, "asc_enqueue: reqp %x\n", (unsigned) reqp); return; } @@ -5537,15 +7771,15 @@ { REQP reqp; - ASC_DBG2(1, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid); + ASC_DBG2(3, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID); + ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); if ((reqp = ascq->q_first[tid]) != NULL) { - ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)); + ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); ascq->q_first[tid] = REQPNEXT(reqp); /* If the queue is empty, clear its bit and the last pointer. */ if (ascq->q_first[tid] == NULL) { - ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); ASC_ASSERT(ascq->q_last[tid] == reqp); ascq->q_last[tid] = NULL; } @@ -5556,7 +7790,7 @@ REQTIMESTAT("asc_dequeue", ascq, reqp, tid); #endif /* ADVANSYS_STATS */ } - ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp); + ASC_DBG1(3, "asc_dequeue: reqp %x\n", (unsigned) reqp); return reqp; } @@ -5586,9 +7820,9 @@ REQP firstp, lastp; int i; - ASC_DBG2(1, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid); + ASC_DBG2(3, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ASC_MAX_TID)); + ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID)); /* * If 'tid' is not ASC_TID_ALL, return requests only for @@ -5597,14 +7831,14 @@ */ if (tid != ASC_TID_ALL) { /* Return all requests for the specified 'tid'. */ - if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) { + if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) { /* List is empty; Set first and last return pointers to NULL. */ firstp = lastp = NULL; } else { firstp = ascq->q_first[tid]; lastp = ascq->q_last[tid]; ascq->q_first[tid] = ascq->q_last[tid] = NULL; - ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); #ifdef ADVANSYS_STATS { REQP reqp; @@ -5618,8 +7852,8 @@ } else { /* Return all requests for all tids. */ firstp = lastp = NULL; - for (i = 0; i <= ASC_MAX_TID; i++) { - if (ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(i)) { + for (i = 0; i <= ADV_MAX_TID; i++) { + if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) { if (firstp == NULL) { firstp = ascq->q_first[i]; lastp = ascq->q_last[i]; @@ -5629,7 +7863,7 @@ lastp = ascq->q_last[i]; } ascq->q_first[i] = ascq->q_last[i] = NULL; - ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i); #ifdef ADVANSYS_STATS ascq->q_cur_cnt[i] = 0; #endif /* ADVANSYS_STATS */ @@ -5647,7 +7881,7 @@ if (lastpp) { *lastpp = lastp; } - ASC_DBG1(1, "asc_dequeue_list: firstp %x\n", (unsigned) firstp); + ASC_DBG1(3, "asc_dequeue_list: firstp %x\n", (unsigned) firstp); return firstp; } @@ -5668,13 +7902,13 @@ int tid; int ret = ASC_FALSE; - ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %x\n", + ASC_DBG2(3, "asc_rmqueue: ascq %x, reqp %x\n", (unsigned) ascq, (unsigned) reqp); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID); + ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); /* * Handle the common case of 'reqp' being the first @@ -5685,7 +7919,7 @@ ascq->q_first[tid] = REQPNEXT(reqp); /* If the queue is now empty, clear its bit and the last pointer. */ if (ascq->q_first[tid] == NULL) { - ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); + ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid); ASC_ASSERT(ascq->q_last[tid] == reqp); ascq->q_last[tid] = NULL; } @@ -5721,7 +7955,7 @@ } ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0); #endif /* ADVANSYS_STATS */ - ASC_DBG2(1, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret); + ASC_DBG2(3, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret); return ret; } @@ -5736,22 +7970,22 @@ int tid; int ret = ASC_FALSE; - ASC_DBG2(1, "asc_isqueued: ascq %x, reqp %x\n", + ASC_DBG2(3, "asc_isqueued: ascq %x, reqp %x\n", (unsigned) ascq, (unsigned) reqp); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); ASC_ASSERT(reqp != NULL); tid = REQPTID(reqp); - ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID); + ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID); for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) { - ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)); + ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)); if (treqp == reqp) { ret = ASC_TRUE; break; } } - ASC_DBG1(1, "asc_isqueued: ret %x\n", ret); + ASC_DBG1(3, "asc_isqueued: ret %x\n", ret); return ret; } @@ -5763,9 +7997,9 @@ STATIC void asc_execute_queue(asc_queue_t *ascq) { - ASC_SCSI_BIT_ID_TYPE scan_tidmask; + ADV_SCSI_BIT_ID_TYPE scan_tidmask; REQP reqp; - int i; + int i; ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); @@ -5775,13 +8009,13 @@ */ scan_tidmask = ascq->q_tidmask; do { - for (i = 0; i <= ASC_MAX_TID; i++) { - if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) { + for (i = 0; i <= ADV_MAX_TID; i++) { + if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) { if ((reqp = asc_dequeue(ascq, i)) == NULL) { - scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + scan_tidmask &= ~ADV_TID_TO_TIDMASK(i); } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp) == ASC_BUSY) { - scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + scan_tidmask &= ~ADV_TID_TO_TIDMASK(i); /* Put the request back at front of the list. */ asc_enqueue(ascq, reqp, ASC_FRONT); } @@ -5810,6 +8044,7 @@ int leftlen; int totlen; int len; + int chip_scsi_id; int i; boardp = ASC_BOARDP(shp); @@ -5820,36 +8055,177 @@ "\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no); ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, "Target Ids Detected:"); + if (ASC_NARROW_BOARD(boardp)) { + chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; + } else { + chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; + } + + len = asc_prt_line(cp, leftlen, "Target IDs Detected:"); ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if (boardp->asc_dvc_cfg.chip_scsi_id == i) { - continue; - } else if (boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) { - len = asc_prt_line(cp, leftlen, " %d,", i); + for (i = 0; i <= ADV_MAX_TID; i++) { + if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) { + len = asc_prt_line(cp, leftlen, " %X,", i); ASC_PRT_NEXT(); } } - len = asc_prt_line(cp, leftlen, " (%d=Host Adapter)\n", - boardp->asc_dvc_cfg.chip_scsi_id); + len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id); ASC_PRT_NEXT(); - return totlen; + return totlen; } /* - * asc_prt_board_eeprom() - * - * Print board EEPROM configuration. - * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). + * Display Wide Board BIOS Information. + */ +STATIC int +asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen) +{ + asc_board_t *boardp; + int leftlen; + int totlen; + int len; + int upgrade = ASC_FALSE; + ushort major, minor, letter; + + boardp = ASC_BOARDP(shp); + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: "); + ASC_PRT_NEXT(); + + /* + * If the BIOS saved a valid signature, then fill in + * the BIOS code segment base address. + */ + if (boardp->bios_signature != 0x55AA) { + len = asc_prt_line(cp, leftlen, "Pre-3.1\n"); + ASC_PRT_NEXT(); + upgrade = ASC_TRUE; + } else { + major = (boardp->bios_version >> 12) & 0xF; + minor = (boardp->bios_version >> 8) & 0xF; + letter = (boardp->bios_version & 0xFF); + + len = asc_prt_line(cp, leftlen, "%d.%d%c\n", + major, minor, letter >= 26 ? '?' : letter + 'A'); + ASC_PRT_NEXT(); + + /* Current available ROM BIOS release is 3.1E. */ + if (major < 3 || (major <= 3 && minor < 1) || + (major <= 3 && minor <= 1 && letter < ('E'- 'A'))) { + upgrade = ASC_TRUE; + } + } + if (upgrade == ASC_TRUE) { + len = asc_prt_line(cp, leftlen, +"Newer version of ROM BIOS available: ftp://ftp.advansys.com/pub\n"); + ASC_PRT_NEXT(); + } + + return totlen; +} + +/* + * Add serial number to information bar if signature AAh + * is found in at bit 15-9 (7 bits) of word 1. + * + * Serial Number consists 12 alpha-numeric digits. + * + * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits) + * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits) + * 3-4 - Product ID (0-99) Word0: 10-0 (11 bits) + * 5 - Product revision Word0: " " + * + * Signature Word1: 15-9 (7 bits) + * 6 - Year (4-9) Word1: 8-6 (3 bits) + * 7-8 - Week of the year Word1: 5-0 (6 bits) + * + * 9-12 - Serial Number Word2: 15-0 (16 bits) + * + * Note 1: Only production cards will have a serial number. + * + * Note 2: Signature is most significant 7 bits (0xFE). + * + * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE. + */ +STATIC int +asc_get_eeprom_string(ushort *serialnum, uchar *cp) +{ + ushort w, num; + + if ((serialnum[1] & 0xFE00) != ((ushort) 0xAA << 8)) { + return ASC_FALSE; + } else { + /* + * First word - 6 digits. + */ + w = serialnum[0]; + + /* Product type - 1st digit. */ + *cp++ = 'A' + ((w & 0xE000) >> 13); + + /* Manufacturing location - 2nd digit. */ + *cp++ = 'A' + ((w & 0x1C00) >> 10); + + /* Product ID - 3rd, 4th digits. */ + num = w & 0x3FF; + *cp++ = '0' + (num / 100); + num %= 100; + *cp++ = '0' + (num / 10); + + /* Product revision - 5th digit. */ + *cp++ = 'A' + (num % 10); + + /* + * Second word + */ + w = serialnum[1]; + + /* Year - 6th digit. */ + *cp++ = '0' + ((w & 0x1C0) >> 6); + + /* Week of year - 7th, 8th digits. */ + num = w & 0x003F; + *cp++ = '0' + num / 10; + num %= 10; + *cp++ = '0' + num; + + /* + * Third word + */ + w = serialnum[2]; + + /* Serial number - 9th digit. */ + *cp++ = 'A' + (w / 1000); + + /* 10th, 11th, 12th digits. */ + num = w % 1000; + *cp++ = '0' + num / 100; + num %= 100; + *cp++ = '0' + num / 10; + num %= 10; + *cp++ = '0' + num; + + *cp = '\0'; /* Null Terminate the string. */ + return ASC_TRUE; + } +} + +/* + * asc_prt_asc_board_eeprom() + * + * Print board EEPROM configuration. + * + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). * * Return the number of characters copied into 'cp'. No more than * 'cplen' characters will be copied to 'cp'. */ STATIC int -asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) +asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) { asc_board_t *boardp; ASC_DVC_VAR *asc_dvc_varp; @@ -5859,10 +8235,11 @@ ASCEEP_CONFIG *ep; int i; int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 }; + uchar serialstr[13]; boardp = ASC_BOARDP(shp); - asc_dvc_varp = &boardp->asc_dvc_var; - ep = &boardp->eep_config; + asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; + ep = &boardp->eep_config.asc_eep; leftlen = cplen; totlen = len = 0; @@ -5871,17 +8248,48 @@ "\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no); ASC_PRT_NEXT(); + if (asc_get_eeprom_string((ushort *) &ep->adapter_info[0], serialstr) == + ASC_TRUE) { + len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr); + ASC_PRT_NEXT(); + } else { + if (ep->adapter_info[5] == 0xBB) { + len = asc_prt_line(cp, leftlen, + " Default Settings Used for EEPROM-less Adapter.\n"); + ASC_PRT_NEXT(); + } else { + len = asc_prt_line(cp, leftlen, + " Serial Number Signature Not Present.\n"); + ASC_PRT_NEXT(); + } + } + len = asc_prt_line(cp, leftlen, " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, +" cntl %x, no_scam %x\n", + ep->cntl, ep->no_scam); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Target ID: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %d", i); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, " Disconnects: "); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->disc_enable & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + len = asc_prt_line(cp, leftlen, " %c", + (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5891,8 +8299,8 @@ " Command Queuing: "); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->use_cmd_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + len = asc_prt_line(cp, leftlen, " %c", + (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5902,8 +8310,8 @@ " Start Motor: "); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->start_motor & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + len = asc_prt_line(cp, leftlen, " %c", + (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5913,8 +8321,8 @@ " Synchronous Transfer:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d:%c", - i, (ep->init_sdtr & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + len = asc_prt_line(cp, leftlen, " %c", + (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -5931,6 +8339,156 @@ } /* + * asc_prt_adv_board_eeprom() + * + * Print board EEPROM configuration. + * + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). + * + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ +STATIC int +asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) +{ + asc_board_t *boardp; + ADV_DVC_VAR *adv_dvc_varp; + int leftlen; + int totlen; + int len; + int i; + char *termstr; + uchar serialstr[13]; + ADVEEP_CONFIG *ep; + + boardp = ASC_BOARDP(shp); + adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; + ep = &boardp->eep_config.adv_eep; + + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, +"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no); + ASC_PRT_NEXT(); + + if (asc_get_eeprom_string(&ep->serial_number_word1, serialstr) == + ASC_TRUE) { + len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr); + ASC_PRT_NEXT(); + } else { + len = asc_prt_line(cp, leftlen, + " Serial Number Signature Not Present.\n"); + ASC_PRT_NEXT(); + } + + len = asc_prt_line(cp, leftlen, +" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", + ep->adapter_scsi_id, ep->max_host_qng, ep->max_dvc_qng); + ASC_PRT_NEXT(); + + switch (ep->termination) { + case 1: + termstr = "Low Off/High Off"; + break; + case 2: + termstr = "Low Off/High On"; + break; + case 3: + termstr = "Low On/High On"; + break; + default: + case 0: + termstr = "Automatic"; + break; + } + + len = asc_prt_line(cp, leftlen, +" termination: %u (%s), bios_ctrl: %x\n", + ep->termination, termstr, ep->bios_ctrl); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Target ID: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %X", i); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Disconnects: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Command Queuing: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Start Motor: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Synchronous Transfer:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Ultra Transfer: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Wide Transfer: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %c", + (ep->wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + return totlen; +} + +/* * asc_prt_driver_conf() * * Note: no single line should be greater than ASC_PRTLINE_SIZE, @@ -5946,6 +8504,7 @@ int leftlen; int totlen; int len; + int chip_scsi_id; #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) int i; #endif /* version >= v1.3.89 */ @@ -5992,65 +8551,82 @@ #endif /* version >= v1.3.57 */ ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, -" flags %x, last_reset %x, jiffies %x\n", - ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies); + len = asc_prt_line(cp, leftlen, " flags %x, last_reset %x, jiffies %x\n", + boardp->flags, boardp->last_reset, jiffies); ASC_PRT_NEXT(); + if (ASC_NARROW_BOARD(boardp)) { + chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; + } else { + chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; + } + #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) - len = asc_prt_line(cp, leftlen, -" queue_depth: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { - continue; + if (boardp->flags & ASC_SELECT_QUEUE_DEPTHS) { + len = asc_prt_line(cp, leftlen, " queue_depth:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + if (boardp->device[i] == NULL) { + continue; + } + len = asc_prt_line(cp, leftlen, " %X:%d", + i, boardp->device[i]->queue_depth); + ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_depth); + len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); #endif /* version >= v1.3.89 */ #if ASC_QUEUE_FLOW_CONTROL - len = asc_prt_line(cp, leftlen, -" queue_curr_depth:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { - continue; + if (ASC_NARROW_BOARD(boardp)) { + len = asc_prt_line(cp, leftlen, " queue_curr_depth:"); + ASC_PRT_NEXT(); + /* Use ASC_MAX_TID for Narrow Board. */ + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + if (boardp->device[i] == NULL) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%d", + i, boardp->device[i]->queue_curr_depth); + ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_curr_depth); + len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, -" queue_count: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { - continue; + len = asc_prt_line(cp, leftlen, " queue_count:"); + ASC_PRT_NEXT(); + /* Use ASC_MAX_TID for Narrow Board. */ + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + if (boardp->device[i] == NULL) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%d", + i, boardp->device[i]->queue_count); + ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, " %d:%d", - i, boardp->device[i]->queue_count); + len = asc_prt_line(cp, leftlen, "\n"); ASC_PRT_NEXT(); } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); #endif /* ASC_QUEUE_FLOW_CONTROL */ - return totlen; + return totlen; } /* - * asc_prt_board_info() + * asc_prt_asc_board_info() * * Print dynamic board configuration information. * @@ -6061,7 +8637,7 @@ * 'cplen' characters will be copied to 'cp'. */ STATIC int -asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen) +asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen) { asc_board_t *boardp; int leftlen; @@ -6072,8 +8648,8 @@ int i; boardp = ASC_BOARDP(shp); - v = &boardp->asc_dvc_var; - c = &boardp->asc_dvc_cfg; + v = &boardp->dvc_var.asc_dvc_var; + c = &boardp->dvc_cfg.asc_dvc_cfg; leftlen = cplen; totlen = len = 0; @@ -6084,30 +8660,30 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" chip_version %u, lib_version %u, lib_serial_no %u, mcode_date %u\n", +" chip_version %u, lib_version %x, lib_serial_no %u, mcode_date %x\n", c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" mcode_version %u, err_code %u\n", +" mcode_version %x, err_code %u\n", c->mcode_version, v->err_code); ASC_PRT_NEXT(); /* Current number of commands waiting for the host. */ len = asc_prt_line(cp, leftlen, -" Total Command Pending: %d\n", v->cur_total_qng); +" Total Command Pending: %d\n", v->cur_total_qng); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" Command Queuing: "); +" Command Queuing:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%c", - i, (v->use_tagged_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -6115,11 +8691,11 @@ /* Current number of commands waiting for a device. */ len = asc_prt_line(cp, leftlen, -" Command Queue Pending: "); +" Command Queue Pending:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]); @@ -6130,11 +8706,11 @@ /* Current limit on number of commands that can be sent to a device. */ len = asc_prt_line(cp, leftlen, -" Command Queue Limit: "); +" Command Queue Limit:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]); @@ -6145,14 +8721,14 @@ /* Indicate whether the device has returned queue full status. */ len = asc_prt_line(cp, leftlen, -" Command Queue Full: "); +" Command Queue Full:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } - if (boardp->queue_full & ASC_TIX_TO_TARGET_ID(i)) { + if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) { len = asc_prt_line(cp, leftlen, " %d:Y-%d", i, boardp->queue_full_cnt[i]); } else { @@ -6164,15 +8740,15 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" Synchronous Transfer: "); +" Synchronous Transfer:"); ASC_PRT_NEXT(); for (i = 0; i <= ASC_MAX_TID; i++) { - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } len = asc_prt_line(cp, leftlen, " %d:%c", - i, (v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N'); + i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); @@ -6181,15 +8757,15 @@ for (i = 0; i <= ASC_MAX_TID; i++) { uchar syn_period_ix; - if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || - ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) { + if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { continue; } - if ((v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) == 0) { + if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { continue; } syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1); - len = asc_prt_line(cp, leftlen, " %d:", i); + len = asc_prt_line(cp, leftlen, " %d:", i); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, @@ -6204,20 +8780,207 @@ ASC_PRT_NEXT(); } - return totlen; + return totlen; } /* - * asc_proc_copy() + * asc_prt_adv_board_info() * - * Copy proc information to a read buffer taking into account the current - * read offset in the file and the remaining space in the read buffer. - */ -STATIC int -asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, - char *cp, int cplen) -{ - int cnt = 0; + * Print dynamic board configuration information. + * + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). + * + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ +STATIC int +asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen) +{ + asc_board_t *boardp; + int leftlen; + int totlen; + int len; + int i; + ADV_DVC_VAR *v; + ADV_DVC_CFG *c; + AdvPortAddr iop_base; + ushort chip_scsi_id; + ushort lramword; + uchar lrambyte; + ushort sdtr_able; + ushort period; + + boardp = ASC_BOARDP(shp); + v = &boardp->dvc_var.adv_dvc_var; + c = &boardp->dvc_cfg.adv_dvc_cfg; + iop_base = v->iop_base; + chip_scsi_id = v->chip_scsi_id; + + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, +"\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n", + shp->host_no); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" iop_base %lx, cable_detect: %X, err_code %u, idle_cmd_done %u\n", + v->iop_base, + AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT, + v->err_code, v->idle_cmd_done); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" chip_version %u, lib_version %x, mcode_date %x, mcode_version %x\n", + c->chip_version, c->lib_version, c->mcode_date, c->mcode_version); + ASC_PRT_NEXT(); + + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, lramword); + len = asc_prt_line(cp, leftlen, +" Queuing Enabled:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + len = asc_prt_line(cp, leftlen, " %X:%c", + i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Queue Limit:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i, lrambyte); + + len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Command Pending:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i, lrambyte); + + len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, lramword); + len = asc_prt_line(cp, leftlen, +" Wide Enabled:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + len = asc_prt_line(cp, leftlen, " %X:%c", + i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Transfer Bit Width:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i), + lramword); + len = asc_prt_line(cp, leftlen, " %X:%d", + i, (lramword & 0x8000) ? 16 : 8); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); + len = asc_prt_line(cp, leftlen, +" Synchronous Enabled:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ADV_MAX_TID; i++) { + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + + len = asc_prt_line(cp, leftlen, " %X:%c", + i, (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + for (i = 0; i <= ADV_MAX_TID; i++) { + + AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i), + lramword); + lramword &= ~0x8000; + + if ((chip_scsi_id == i) || + ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0) || + (lramword == 0)) { + continue; + } + + len = asc_prt_line(cp, leftlen, " %X:", i); + ASC_PRT_NEXT(); + + period = (((lramword >> 8) * 25) + 50)/4; + + len = asc_prt_line(cp, leftlen, + " Transfer Period Factor: %d (%d.%d Mhz),", + period, 250/period, ASC_TENTHS(250, period)); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n", + lramword & 0x1F); + ASC_PRT_NEXT(); + } + + return totlen; +} + +/* + * asc_proc_copy() + * + * Copy proc information to a read buffer taking into account the current + * read offset in the file and the remaining space in the read buffer. + */ +STATIC int +asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, + char *cp, int cplen) +{ + int cnt = 0; ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n", (unsigned) offset, (unsigned) advoffset, cplen); @@ -6413,7 +9176,6 @@ *inbuf = inpw(iop_base); } - /* * void DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords) * @@ -6531,6 +9293,81 @@ /* + * --- Functions Required by the Adv Library + */ + +/* + * DvcGetPhyAddr() + * + * Return the physical address of 'vaddr' and set '*lenp' to the + * number of physically contiguous bytes that follow 'vaddr'. + * 'flag' indicates the type of structure whose physical address + * is being translated. + * + * Note: Because Linux currently doesn't page the kernel and all + * kernel buffers are physically contiguous, leave '*lenp' unchanged. + */ +ulong +DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq, + uchar *vaddr, long *lenp, int flag) +{ + ulong paddr; + +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0) + paddr = (ulong) vaddr; +#else /* version >= v2.0.0 */ + paddr = virt_to_bus(vaddr); +#endif /* version >= v2.0.0 */ + + ASC_DBG4(4, + "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n", + (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), paddr); + + return paddr; +} + +/* + * Read a PCI configuration byte. + */ +ASC_INITFUNC( +STATIC uchar +DvcAdvReadPCIConfigByte( + ADV_DVC_VAR *asc_dvc, + ushort offset) +) +{ + PCI_DATA pciData; + + pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); + pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); + pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); + pciData.offset = offset; + pciData.type = pci_scan_method; + return asc_get_cfg_byte(&pciData); +} + +/* + * Write a PCI configuration byte. + */ +ASC_INITFUNC( +STATIC void +DvcAdvWritePCIConfigByte( + ADV_DVC_VAR *asc_dvc, + ushort offset, + uchar byte_data) +) +{ + PCI_DATA pciData; + + pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); + pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); + pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); + pciData.offset = offset; + pciData.type = pci_scan_method; + asc_put_cfg_byte(&pciData, byte_data); +} + +/* * --- Tracing and Debugging Functions */ @@ -6550,15 +9387,19 @@ int leftlen; int totlen; int len; - struct asc_stats *s; + struct asc_stats *s; int i; + ushort chip_scsi_id; + asc_board_t *boardp; asc_queue_t *active; asc_queue_t *waiting; leftlen = cplen; totlen = len = 0; - s = &ASC_BOARDP(shp)->asc_stats; + boardp = ASC_BOARDP(shp); + s = &boardp->asc_stats; + len = asc_prt_line(cp, leftlen, "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no); ASC_PRT_NEXT(); @@ -6569,13 +9410,24 @@ ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" check_interrupt %lu, interrupt %lu, callback %lu, done %lu\n", - s->check_interrupt, s->interrupt, s->callback, s->done); +" interrupt %lu, callback %lu, done %lu\n", + s->interrupt, s->callback, s->done); ASC_PRT_NEXT(); len = asc_prt_line(cp, leftlen, -" asc_noerror %lu, asc_busy %lu, asc_error %lu, asc_unknown %lu\n", - s->asc_noerror, s->asc_busy, s->asc_error, s->asc_unknown); +" exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n", + s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown); + ASC_PRT_NEXT(); + + if (ASC_NARROW_BOARD(boardp)) { + len = asc_prt_line(cp, leftlen, +" build_error %lu\n", + s->build_error); + } else { + len = asc_prt_line(cp, leftlen, +" build_error %lu, build_noreq %lu, build_nosg %lu\n", + s->build_error, s->adv_build_noreq, s->adv_build_nosg); + } ASC_PRT_NEXT(); /* @@ -6629,12 +9481,25 @@ * Display request queuing statistics. */ len = asc_prt_line(cp, leftlen, -" Active and Waiting Request Queues (time unit: %d HZ):\n", HZ); +" Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ); ASC_PRT_NEXT(); active = &ASC_BOARDP(shp)->active; waiting = &ASC_BOARDP(shp)->waiting; - for (i = 0; i < ASC_MAX_TID + 1; i++) { + + if (ASC_NARROW_BOARD(boardp)) { + chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; + } else { + chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; + } + + for (i = 0; i <= ADV_MAX_TID; i++) { + + if ((chip_scsi_id == i) || + ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { + continue; + } + if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) { len = asc_prt_line(cp, leftlen, " target %d\n", i); ASC_PRT_NEXT(); @@ -6674,22 +9539,20 @@ STATIC void asc_prt_scsi_host(struct Scsi_Host *s) { + asc_board_t *boardp; + + boardp = ASC_BOARDP(s); + printk("Scsi_Host at addr %x\n", (unsigned) s); printk( " next %x, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n", (unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no, (unsigned) s->last_reset); -#ifdef ERIC_neverdef /* { */ - /* - * This information is private to the mid-layer scsi and the - * the low-level drivers shouldn't even be aware that it is there. - */ printk( " host_wait %x, host_queue %x, hostt %x, block %x,\n", (unsigned) s->host_wait, (unsigned) s->host_queue, (unsigned) s->hostt, (unsigned) s->block); -#endif /* ERIC_neverdef */ /* } */ printk( " wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n", @@ -6704,8 +9567,13 @@ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma, s->loaded_as_module); - asc_prt_dvc_var(&ASC_BOARDP(s)->asc_dvc_var); - asc_prt_dvc_cfg(&ASC_BOARDP(s)->asc_dvc_cfg); + if (ASC_NARROW_BOARD(boardp)) { + asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var); + asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg); + } else { + asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var); + asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg); + } } /* @@ -6763,10 +9631,10 @@ } /* - * asc_prt_dvc_var() + * asc_prt_asc_dvc_var() */ STATIC void -asc_prt_dvc_var(ASC_DVC_VAR *h) +asc_prt_asc_dvc_var(ASC_DVC_VAR *h) { printk("ASC_DVC_VAR at addr %x\n", (unsigned) h); @@ -6805,10 +9673,10 @@ } /* - * asc_prt_dvc_cfg() + * asc_prt_asc_dvc_cfg() */ STATIC void -asc_prt_dvc_cfg(ASC_DVC_CFG *h) +asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h) { printk("ASC_DVC_CFG at addr %x\n", (unsigned) h); @@ -6822,7 +9690,7 @@ h->chip_version); printk( -" pci_device_id %d, lib_serial_no %d, lib_version %d, mcode_date %d,\n", +" pci_device_id %d, lib_serial_no %x, lib_version %x, mcode_date %x,\n", h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date); printk( @@ -6831,10 +9699,10 @@ } /* - * asc_prt_scsi_q() + * asc_prt_asc_scsi_q() */ STATIC void -asc_prt_scsi_q(ASC_SCSI_Q *q) +asc_prt_asc_scsi_q(ASC_SCSI_Q *q) { ASC_SG_HEAD *sgp; int i; @@ -6869,10 +9737,10 @@ } /* - * asc_prt_qdone_info() + * asc_prt_asc_qdone_info() */ STATIC void -asc_prt_qdone_info(ASC_QDONE_INFO *q) +asc_prt_asc_qdone_info(ASC_QDONE_INFO *q) { printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q); printk( @@ -6885,71 +9753,223 @@ } /* - * asc_prt_hex() + * asc_prt_adv_dvc_var() * - * Print hexadecimal output in 4 byte groupings 32 bytes - * or 8 double-words per line. + * Display an ADV_DVC_VAR structure. */ STATIC void -asc_prt_hex(char *f, uchar *s, int l) +asc_prt_adv_dvc_var(ADV_DVC_VAR *h) { - int i; - int j; - int k; - int m; + printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h); - printk("%s: (%d bytes)\n", f, l); + printk( +" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n", + (ulong) h->iop_base, h->err_code, (unsigned) h->ultra_able); - for (i = 0; i < l; i += 32) { - - /* Display a maximum of 8 double-words per line. */ - if ((k = (l - i) / 4) >= 8) { - k = 8; - m = 0; - } else { - m = (l - i) % 4 ; - } + printk( +" isr_callback 0x%x, sdtr_able 0x%x, wdtr_able 0x%x\n", + (unsigned) h->isr_callback, (unsigned) h->wdtr_able, + (unsigned) h->sdtr_able); - for (j = 0; j < k; j++) { - printk(" %2.2X%2.2X%2.2X%2.2X", - (unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1], - (unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]); - } + printk( +" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n", + (unsigned) h->start_motor, + (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no); - switch (m) { - case 0: - default: - break; - case 1: - printk(" %2.2X", - (unsigned) s[i+(j*4)]); - break; - case 2: - printk(" %2.2X%2.2X", - (unsigned) s[i+(j*4)], - (unsigned) s[i+(j*4)+1]); - break; - case 3: - printk(" %2.2X%2.2X%2.2X", - (unsigned) s[i+(j*4)+1], - (unsigned) s[i+(j*4)+2], - (unsigned) s[i+(j*4)+3]); - break; - } + printk( +" max_host_qng 0x%x, cur_host_qng 0x%x, max_dvc_qng 0x%x\n", + (unsigned) h->max_host_qng, (unsigned) h->cur_host_qng, + (unsigned) h->max_dvc_qng); + + printk( +" no_scam 0x%x, tagqng_able 0x%x, chip_scsi_id 0x%x, cfg 0x%lx\n", + (unsigned) h->no_scam, (unsigned) h->tagqng_able, + (unsigned) h->chip_scsi_id, (ulong) h->cfg); - printk("\n"); - } } -#endif /* ADVANSYS_DEBUG */ -#ifdef ADVANSYS_ASSERT /* - * interrupts_enabled() + * asc_prt_adv_dvc_cfg() * - * Return 1 if interrupts are enabled, otherwise return 0. + * Display an ADV_DVC_CFG structure. */ -STATIC int -interrupts_enabled(void) +STATIC void +asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h) +{ + printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h); + + printk( +" disc_enable 0x%x, termination 0x%x\n", + h->disc_enable, h->termination); + + printk( +" chip_version 0x%x, mcode_date 0x%x\n", + h->chip_version, h->mcode_date); + + printk( +" mcode_version 0x%x, pci_device_id 0x%x, lib_version 0x%x\n", + h->mcode_version, h->pci_device_id, h->lib_version); + + printk( +" control_flag 0x%x, pci_slot_info 0x%x\n", + h->control_flag, h->pci_slot_info); +} + +/* + * asc_prt_adv_scsi_req_q() + * + * Display an ADV_SCSI_REQ_Q structure. + */ +STATIC void +asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) +{ + int i; + struct asc_sg_block *sg_ptr; + + printk("ADV_SCSI_REQ_Q at addr %x\n", (unsigned) q); + + printk( +" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n", + q->target_id, q->target_lun, q->srb_ptr, q->a_flag); + + printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n", + q->cntl, q->data_addr, q->vdata_addr); + + printk( +" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", + q->data_cnt, q->sense_addr, q->sense_len); + + printk( +" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n", + q->cdb_len, q->done_status, q->host_status, q->scsi_status); + + printk( +" vsense_addr 0x%lx, scsiq_ptr 0x%lx, ux_wk_data_cnt %lu\n", + (ulong) q->vsense_addr, (ulong) q->scsiq_ptr, + (ulong) q->ux_wk_data_cnt); + + printk( +" sg_list_ptr 0x%lx, sg_real_addr 0x%lx, sg_entry_cnt %u\n", + (ulong) q->sg_list_ptr, (ulong) q->sg_real_addr, q->sg_entry_cnt); + + printk( +" ux_sg_ix %u, orig_sense_len %u\n", + q->ux_sg_ix, q->orig_sense_len); + + /* Display the request's ADV_SG_BLOCK structures. */ + for (sg_ptr = q->sg_list_ptr, i = 0; sg_ptr != NULL; + sg_ptr = sg_ptr->sg_ptr, i++) { + /* + * 'sg_ptr' is a physical address. Convert it to a virtual + * address by indexing 'i' into the virtual address array + * 'sg_list_ptr'. + * + * At the end of the each iteration of the loop 'sg_ptr' is + * converted back into a physical address by setting 'sg_ptr' + * to the next pointer 'sg_ptr->sg_ptr'. + */ + sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[i]); + asc_prt_adv_sgblock(i, sg_ptr); + } +} + +/* + * asc_prt_adv_sgblock() + * + * Display an ADV_SG_BLOCK structure. + */ +STATIC void +asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b) +{ + int i, s; + + /* Calculate starting entry number for the current block. */ + s = sgblockno * NO_OF_SG_PER_BLOCK; + + printk(" ADV_SG_BLOCK at addr 0x%lx (sgblockno %lu)\n", + (ulong) b, (ulong) sgblockno); + printk( +" first_entry_no %lu, last_entry_no %lu, sg_ptr 0x%lx\n", + (ulong) b->first_entry_no, (ulong) b->last_entry_no, (ulong) b->sg_ptr); + ASC_ASSERT(b->first_entry_no - s >= 0); + ASC_ASSERT(b->last_entry_no - s >= 0); + ASC_ASSERT(b->last_entry_no - s <= NO_OF_SG_PER_BLOCK); + ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK); + ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK); + ASC_ASSERT(b->first_entry_no - s <= b->last_entry_no - s); + for (i = b->first_entry_no - s; i <= b->last_entry_no - s; i++) { + printk(" [%lu]: sg_addr 0x%lx, sg_count 0x%lx\n", + (ulong) i, (ulong) b->sg_list[i].sg_addr, + (ulong) b->sg_list[i].sg_count); + } +} + +/* + * asc_prt_hex() + * + * Print hexadecimal output in 4 byte groupings 32 bytes + * or 8 double-words per line. + */ +STATIC void +asc_prt_hex(char *f, uchar *s, int l) +{ + int i; + int j; + int k; + int m; + + printk("%s: (%d bytes)\n", f, l); + + for (i = 0; i < l; i += 32) { + + /* Display a maximum of 8 double-words per line. */ + if ((k = (l - i) / 4) >= 8) { + k = 8; + m = 0; + } else { + m = (l - i) % 4 ; + } + + for (j = 0; j < k; j++) { + printk(" %2.2X%2.2X%2.2X%2.2X", + (unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1], + (unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]); + } + + switch (m) { + case 0: + default: + break; + case 1: + printk(" %2.2X", + (unsigned) s[i+(j*4)]); + break; + case 2: + printk(" %2.2X%2.2X", + (unsigned) s[i+(j*4)], + (unsigned) s[i+(j*4)+1]); + break; + case 3: + printk(" %2.2X%2.2X%2.2X", + (unsigned) s[i+(j*4)+1], + (unsigned) s[i+(j*4)+2], + (unsigned) s[i+(j*4)+3]); + break; + } + + printk("\n"); + } +} +#endif /* ADVANSYS_DEBUG */ + +#ifdef ADVANSYS_ASSERT +/* + * interrupts_enabled() + * + * Return 1 if interrupts are enabled, otherwise return 0. + */ +STATIC int +interrupts_enabled(void) { int flags; @@ -6975,6 +9995,7 @@ ) { PortAddr eisa_cfg_iop; + eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | (PortAddr) (ASC_EISA_CFG_IOP_MASK); return (inpw(eisa_cfg_iop)); @@ -6989,6 +10010,7 @@ ) { ushort cfg_lsw; + if (AscGetChipScsiID(iop_base) == new_host_id) { return (new_host_id); } @@ -7007,6 +10029,7 @@ ) { uchar sc; + AscSetBank(iop_base, 1); sc = inp(iop_base + IOP_REG_SC); AscSetBank(iop_base, 0); @@ -7040,6 +10063,7 @@ ) { ushort chip_ver; + chip_ver = AscGetChipVerNo(iop_base); if ( (chip_ver >= ASC_CHIP_MIN_VER_VL) @@ -7079,6 +10103,7 @@ ulong chksum; ushort mcode_word_size; ushort mcode_chksum; + mcode_word_size = (ushort) (mcode_size >> 1); AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size); AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size); @@ -7099,6 +10124,7 @@ ) { ushort sig_word; + if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) { sig_word = AscGetChipSignatureWord(iop_base); if ((sig_word == (ushort) ASC_1000_ID0W) || @@ -7162,6 +10188,7 @@ { int i; PortAddr iop_base; + for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) { if (_asc_def_iop_base[i] > s_addr) { break; @@ -7216,6 +10243,7 @@ { ushort cfg_lsw; uchar chip_irq; + if ((bus_type & ASC_IS_EISA) != 0) { cfg_lsw = AscGetEisaChipCfg(iop_base); chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10); @@ -7232,11 +10260,6 @@ (chip_irq == 7)) { return (0); } -#if CC_PLEXTOR_VL - if (chip_irq == 5) { - return (9); - } -#endif return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1))); } cfg_lsw = AscGetChipCfgLsw(iop_base); @@ -7256,13 +10279,9 @@ ) { ushort cfg_lsw; + if ((bus_type & ASC_IS_VL) != 0) { if (irq_no != 0) { -#if CC_PLEXTOR_VL - if (irq_no == 9) { - irq_no = 14; - } -#endif if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) { irq_no = 0; } else { @@ -7473,7 +10492,6 @@ q_cntl |= QC_REQ_SENSE; -#if CC_CHK_COND_REDO_SDTR if ((asc_dvc->init_sdtr & target_id) != 0) { asc_dvc->sdtr_done &= ~target_id; @@ -7485,7 +10503,6 @@ (uchar) (asc_dvc->max_sdtr_index - 1)], (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); } -#endif AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), @@ -7577,7 +10594,8 @@ boardp->queue_full |= target_id; boardp->queue_full_cnt[tid_no] = cur_dvc_qng; #if ASC_QUEUE_FLOW_CONTROL - if (boardp->device[tid_no]->queue_curr_depth > + if (boardp->device[tid_no] != NULL && + boardp->device[tid_no]->queue_curr_depth > cur_dvc_qng) { boardp->device[tid_no]->queue_curr_depth = cur_dvc_qng; @@ -7602,13 +10620,11 @@ { ushort _val; uchar sg_queue_cnt; + DvcGetQinfo(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG), (ushort *) scsiq, (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2)); -#if !CC_LITTLE_ENDIAN_HOST - AscAdjEndianQDoneInfo(scsiq); -#endif _val = AscReadLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS)); scsiq->q_status = (uchar) _val; @@ -7649,6 +10665,7 @@ REG ASC_QDONE_INFO *scsiq; int false_overrun; ASC_ISR_CALLBACK asc_isr_callback; + iop_base = asc_dvc->iop_base; asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; n_q_used = 1; @@ -7731,18 +10748,13 @@ AscStopChip(iop_base); AscSetChipControl(iop_base, (uchar) (CC_SCSI_RESET | CC_HALT)); - DvcDelayNanoSecond(asc_dvc, 30000); + DvcDelayNanoSecond(asc_dvc, 60000); AscSetChipControl(iop_base, CC_HALT); AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); AscSetChipStatus(iop_base, 0); AscSetChipControl(iop_base, 0); } } -#if CC_CLEAR_LRAM_SRB_PTR - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), - asc_dvc->int_count); -#endif if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { (*asc_isr_callback) (asc_dvc, scsiq); } else { @@ -7781,6 +10793,7 @@ int int_pending; int status; uchar host_flag; + iop_base = asc_dvc->iop_base; int_pending = FALSE; if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) @@ -7819,12 +10832,10 @@ ASCV_HOST_FLAG_B) & (uchar) (~ASC_HOST_FLAG_IN_ISR); AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR)); -#if CC_ASCISR_CHECK_INT_PENDING if ((chipstat & CSW_INT_PENDING) || (int_pending) ) { AscAckInterrupt(iop_base); -#endif int_pending = TRUE; if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) { @@ -7848,9 +10859,7 @@ if ((status & 0x80) != 0) int_pending = ERR; } -#if CC_ASCISR_CHECK_INT_PENDING } -#endif AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); AscSetChipLramAddr(iop_base, saved_ram_addr); AscSetChipControl(iop_base, saved_ctrl_reg); @@ -7867,6 +10876,7 @@ ) { ulong phy_addr; + scsiq->r1.cntl = 0; scsiq->r1.sg_queue_cnt = 0; scsiq->r1.q_no = 0; @@ -7901,155 +10911,156 @@ return (0); } -STATIC uchar _mcode_buf[] ASC_INITDATA = +STATIC uchar _asc_mcode_buf[] ASC_INITDATA = { - 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x79, 0x0D, 0x09, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x23, 0x00, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x88, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40, - 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC2, 0x00, 0x92, 0x80, - 0x08, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x32, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, - 0x4F, 0x00, 0xF5, 0x00, 0x32, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62, - 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00, - 0x00, 0xA3, 0xD6, 0x00, 0x90, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, 0xD8, 0x84, 0xD2, 0xC1, - 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE2, 0x01, 0x90, 0x97, 0xCE, 0x81, 0x00, 0x33, - 0x02, 0x00, 0xAA, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0x02, 0x01, 0x4F, 0x00, - 0x6E, 0x97, 0x07, 0xA6, 0x0C, 0x01, 0x00, 0x33, 0x03, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x03, 0xDE, - 0x00, 0x33, 0x05, 0x00, 0xAA, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, - 0x00, 0xA2, 0x80, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x2C, 0x01, 0x80, 0x81, 0x03, 0x03, 0x80, 0x63, - 0xE2, 0x00, 0x07, 0xA6, 0x3C, 0x01, 0x00, 0x33, 0x04, 0x00, 0xAA, 0x88, 0x03, 0x07, 0x02, 0x01, - 0x04, 0xCA, 0x0D, 0x23, 0x52, 0x98, 0x4D, 0x04, 0xF6, 0x84, 0x05, 0xD8, 0x0D, 0x23, 0x52, 0x98, - 0xCD, 0x04, 0x15, 0x23, 0xE0, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, - 0x06, 0xA3, 0x6A, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xAA, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x76, 0x01, - 0x00, 0x33, 0x0B, 0x00, 0xAA, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xAA, 0x88, - 0x50, 0x04, 0x90, 0x81, 0x06, 0xAB, 0x8A, 0x01, 0x90, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x9A, 0x01, - 0x50, 0x00, 0x00, 0xA3, 0x44, 0x01, 0x00, 0x05, 0x84, 0x81, 0x30, 0x97, 0x02, 0x01, 0x05, 0xC6, - 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xC6, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, - 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xBC, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, - 0x00, 0x33, 0x1B, 0x00, 0xAA, 0x88, 0x06, 0x23, 0x52, 0x98, 0xCD, 0x04, 0xD8, 0x84, 0x06, 0x01, - 0x00, 0xA2, 0xDC, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE2, 0x01, 0xD8, 0x84, 0x80, 0x23, 0xA0, 0x01, - 0xD8, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x08, 0x02, 0x04, 0x01, 0x0C, 0xDE, - 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x6E, 0x97, 0x04, 0x82, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, - 0x4F, 0x00, 0x4C, 0x97, 0x48, 0x04, 0x84, 0x80, 0xDA, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, - 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x67, 0xEB, - 0x11, 0x23, 0xE0, 0x88, 0xEE, 0x97, 0xF4, 0x80, 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x36, 0x02, - 0x00, 0x33, 0x31, 0x00, 0xAA, 0x88, 0x04, 0x01, 0x03, 0xD8, 0x9C, 0x98, 0x44, 0x96, 0x48, 0x82, - 0xD4, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x72, 0x02, 0x07, 0xA6, - 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6, 0x68, 0x02, 0x00, 0x33, 0x10, 0x00, 0xAA, 0x88, - 0x6E, 0x95, 0x4A, 0x82, 0x3A, 0x96, 0x4A, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, - 0x2E, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, - 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, - 0x1C, 0x01, 0x02, 0xA6, 0xB0, 0x02, 0x07, 0xA6, 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6, - 0x12, 0x04, 0x01, 0xA6, 0xBA, 0x02, 0x00, 0xA6, 0xBA, 0x02, 0x00, 0x33, 0x12, 0x00, 0xAA, 0x88, - 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x92, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, - 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, - 0x00, 0x3F, 0x00, 0x00, 0xF0, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE8, 0x02, 0x04, 0x01, - 0x98, 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xAA, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, - 0x68, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x1A, 0x03, 0x00, 0xA6, 0x1A, 0x03, 0x07, 0xA6, 0x12, 0x03, - 0x06, 0xA6, 0x16, 0x03, 0x03, 0xA6, 0x12, 0x04, 0x02, 0xA6, 0x72, 0x02, 0x00, 0x33, 0x33, 0x00, - 0xAA, 0x88, 0x6E, 0x95, 0xF4, 0x82, 0x3A, 0x96, 0xF4, 0x82, 0x6C, 0x98, 0x80, 0x42, 0x68, 0x98, - 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x5A, 0x03, 0x00, 0x43, - 0x87, 0x01, 0x05, 0x05, 0x70, 0x98, 0x68, 0x98, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x52, 0x03, - 0x03, 0xA6, 0x2E, 0x04, 0x06, 0xA6, 0x56, 0x03, 0x01, 0xA6, 0x1C, 0x03, 0x00, 0x33, 0x25, 0x00, - 0xAA, 0x88, 0x6E, 0x95, 0x38, 0x83, 0x3A, 0x96, 0x38, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, - 0x00, 0x33, 0x42, 0x00, 0xAA, 0x88, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x78, 0x03, 0xB1, 0x01, - 0x08, 0x23, 0xB2, 0x01, 0x34, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x98, 0x03, 0xEC, 0x00, - 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x94, 0x03, 0x00, 0xA6, - 0x94, 0x03, 0x08, 0x84, 0x80, 0x42, 0x68, 0x98, 0x01, 0xA6, 0xA2, 0x03, 0x00, 0xA6, 0xBA, 0x03, - 0x08, 0x84, 0x90, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA2, 0x03, 0x07, 0xA6, 0xB0, 0x03, 0xD2, 0x83, - 0x6E, 0x95, 0xA6, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xAA, 0x88, 0x90, 0x98, 0x80, 0x42, 0x00, 0xA6, - 0xBA, 0x03, 0x07, 0xA6, 0xC8, 0x03, 0xD2, 0x83, 0x6E, 0x95, 0xBE, 0x83, 0x00, 0x33, 0x26, 0x00, - 0xAA, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, - 0x08, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0xAA, 0x88, 0x03, 0xA6, 0x06, 0x04, - 0x07, 0xA6, 0xFE, 0x03, 0x06, 0xA6, 0x02, 0x04, 0x00, 0x33, 0x17, 0x00, 0xAA, 0x88, 0x6E, 0x95, - 0xEC, 0x83, 0x3A, 0x96, 0xEC, 0x83, 0x12, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, - 0xAA, 0x88, 0xB6, 0x2D, 0x03, 0xA6, 0x2E, 0x04, 0x07, 0xA6, 0x26, 0x04, 0x06, 0xA6, 0x2A, 0x04, - 0x00, 0x33, 0x30, 0x00, 0xAA, 0x88, 0x6E, 0x95, 0x12, 0x84, 0x3A, 0x96, 0x12, 0x84, 0x1D, 0x01, - 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, - 0x80, 0x63, 0x07, 0xA6, 0x4C, 0x04, 0x00, 0x33, 0x18, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x80, 0x63, - 0xA3, 0x01, 0x07, 0xA4, 0x56, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x78, 0x04, 0x0A, 0xA0, 0x68, 0x04, - 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0xAA, 0x88, 0x0B, 0xA0, 0x74, 0x04, 0xE0, 0x00, 0x00, 0x33, - 0x1E, 0x00, 0xAA, 0x88, 0x42, 0x23, 0xE0, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xD8, 0x04, 0x08, 0x23, - 0x22, 0xA3, 0x94, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xA0, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xB6, 0x04, - 0x42, 0x23, 0xE0, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xA0, 0x04, 0x45, 0x23, 0xE0, 0x88, - 0xEE, 0x97, 0x00, 0xA2, 0xB2, 0x04, 0x9C, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, - 0xF0, 0x81, 0x47, 0x23, 0xE0, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0xEE, 0x97, 0x9C, 0x98, 0x00, 0x33, - 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x08, 0x02, 0x43, 0x23, 0xE0, 0x88, - 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xE6, 0x04, - 0x00, 0x33, 0x27, 0x00, 0xAA, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, - 0xA0, 0x01, 0xEE, 0x97, 0x18, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, - 0x14, 0x05, 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x05, 0xFC, 0x84, 0x30, 0x97, - 0xCD, 0x04, 0x16, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, - 0x26, 0x85, 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x32, 0x05, 0x1D, 0x01, - 0x04, 0xD6, 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, - 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, - 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x52, 0x05, 0x77, 0x04, 0x01, 0x23, - 0xEA, 0x00, 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, - 0xD2, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x80, 0x05, 0xCE, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xAA, 0x88, - 0x04, 0xA0, 0xA6, 0x05, 0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x92, 0x05, 0x1D, 0x01, - 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x4C, 0x97, 0xF6, 0x84, 0x04, 0x23, - 0x02, 0x41, 0x82, 0x01, 0xF6, 0x84, 0x08, 0xA0, 0xAC, 0x05, 0xCE, 0x85, 0x03, 0xA0, 0xB2, 0x05, - 0xCE, 0x85, 0x01, 0xA0, 0xBC, 0x05, 0x88, 0x00, 0x80, 0x63, 0xAA, 0x86, 0x07, 0xA0, 0xC8, 0x05, - 0x06, 0x23, 0x52, 0x98, 0x48, 0x23, 0xE0, 0x88, 0x07, 0x23, 0x80, 0x00, 0xF0, 0x86, 0x80, 0x63, - 0x6E, 0x85, 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x10, 0x06, 0x1D, 0x01, 0x18, 0xD4, - 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0xF2, 0x05, 0x00, 0x33, 0x37, 0x00, - 0xAA, 0x88, 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, 0xE0, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, - 0x06, 0xA6, 0x0A, 0x06, 0x00, 0x33, 0x38, 0x00, 0xAA, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, - 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x28, 0x06, 0x1D, 0x01, - 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, - 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, - 0x80, 0x63, 0x00, 0x63, 0x06, 0xA6, 0x56, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x02, 0xA6, 0xE4, 0x06, - 0x00, 0x33, 0x39, 0x00, 0xAA, 0x88, 0x00, 0x00, 0x01, 0xA0, 0xFE, 0x06, 0xD4, 0x95, 0x83, 0x03, - 0x80, 0x63, 0x06, 0xA6, 0x6A, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x00, 0x01, 0xA0, 0xFE, 0x06, - 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0x86, 0x06, 0x07, 0xA6, 0x6E, 0x05, - 0x00, 0x33, 0x3A, 0x00, 0xAA, 0x88, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x78, 0x06, - 0x06, 0xA6, 0x9E, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x33, 0x3B, 0x00, 0xAA, 0x88, 0x80, 0x67, - 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x63, 0x07, 0xA6, 0xB4, 0x06, 0x00, 0x33, - 0x2A, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xC6, 0x06, - 0x00, 0x33, 0x29, 0x00, 0xAA, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xD2, 0x06, 0xC0, 0x0E, 0x80, 0x63, - 0xBC, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, - 0x80, 0x63, 0x6E, 0x85, 0x80, 0x67, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, - 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x62, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xAA, 0x88, 0x0C, 0xA2, - 0x18, 0x07, 0xD4, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x16, 0x07, 0x07, 0xA6, 0x6E, 0x05, - 0x00, 0x33, 0x3D, 0x00, 0xAA, 0x88, 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, - 0x2E, 0x07, 0x07, 0xA6, 0x6E, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xD8, 0x84, 0x00, 0x63, - 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, - 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, - 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, - 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, - 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, - 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, - 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, - 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xAE, 0x07, 0x00, 0x33, 0x07, 0x00, 0xAA, 0x88, 0x80, 0x05, - 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, - 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xCE, 0x07, 0x00, 0x05, 0xC4, 0x87, 0x00, 0x01, - 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, - 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, - 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0, 0xFE, 0x07, 0x00, 0x88, 0x00, 0x43, - 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, - 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x2E, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, - 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x0E, 0x08, 0xEE, 0x97, 0x18, 0x95, 0x0E, 0x88, 0x73, 0x04, - 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x44, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x30, 0x97, 0xEE, 0x97, - 0x18, 0x95, 0x34, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x4E, 0x08, 0x00, 0x05, 0x38, 0x88, 0x73, 0x04, - 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x60, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xAA, 0x88, - 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B, 0x86, 0x88, 0x38, 0x2B, 0x7C, 0x88, - 0x32, 0x09, 0x31, 0x05, 0x7C, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, - 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, - 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, - 0x00, 0xA0, 0x9C, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, - 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, 0x13, 0x23, 0xE0, 0x88, 0x66, 0x20, 0xC0, 0x20, - 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xCA, 0x88, 0x80, 0x73, 0x80, 0x77, - 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23, 0xE0, 0x88, 0x11, 0x23, - 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xD8, 0x84, + 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xDB, 0x0C, 0x0A, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40, + 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC2, 0x00, 0x92, 0x80, + 0x10, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x3A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, + 0x4F, 0x00, 0xF5, 0x00, 0x3A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62, + 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00, + 0x00, 0xA3, 0xD6, 0x00, 0x98, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE0, 0x84, 0xD2, 0xC1, + 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE2, 0x01, 0x98, 0x97, 0xCE, 0x81, 0x00, 0x33, + 0x02, 0x00, 0xB2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0x02, 0x01, 0x4F, 0x00, + 0x76, 0x97, 0x07, 0xA6, 0x0C, 0x01, 0x00, 0x33, 0x03, 0x00, 0xB2, 0x88, 0x03, 0x03, 0x03, 0xDE, + 0x00, 0x33, 0x05, 0x00, 0xB2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, + 0x00, 0xA2, 0x80, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x2C, 0x01, 0x80, 0x81, 0x03, 0x03, 0x80, 0x63, + 0xE2, 0x00, 0x07, 0xA6, 0x3C, 0x01, 0x00, 0x33, 0x04, 0x00, 0xB2, 0x88, 0x03, 0x07, 0x02, 0x01, + 0x04, 0xCA, 0x0D, 0x23, 0x5A, 0x98, 0x4D, 0x04, 0xFE, 0x84, 0x05, 0xD8, 0x0D, 0x23, 0x5A, 0x98, + 0xCD, 0x04, 0x15, 0x23, 0xE8, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, + 0x06, 0xA3, 0x6A, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xB2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x76, 0x01, + 0x00, 0x33, 0x0B, 0x00, 0xB2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xB2, 0x88, + 0x50, 0x04, 0x90, 0x81, 0x06, 0xAB, 0x8A, 0x01, 0x90, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x9A, 0x01, + 0x50, 0x00, 0x00, 0xA3, 0x44, 0x01, 0x00, 0x05, 0x84, 0x81, 0x38, 0x97, 0x02, 0x01, 0x05, 0xC6, + 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xC6, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, + 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xBC, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, + 0x00, 0x33, 0x1B, 0x00, 0xB2, 0x88, 0x06, 0x23, 0x5A, 0x98, 0xCD, 0x04, 0xE0, 0x84, 0x06, 0x01, + 0x00, 0xA2, 0xDC, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE2, 0x01, 0xE0, 0x84, 0x80, 0x23, 0xA0, 0x01, + 0xE0, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x08, 0x02, 0x04, 0x01, 0x0C, 0xDE, + 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x76, 0x97, 0x04, 0x82, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, + 0x4F, 0x00, 0x54, 0x97, 0x48, 0x04, 0x84, 0x80, 0xE2, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, + 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x67, 0xEB, + 0x11, 0x23, 0xE8, 0x88, 0xF6, 0x97, 0xF4, 0x80, 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x36, 0x02, + 0x00, 0x33, 0x31, 0x00, 0xB2, 0x88, 0x04, 0x01, 0x03, 0xD8, 0xA4, 0x98, 0x4C, 0x96, 0x48, 0x82, + 0xDC, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x72, 0x02, 0x07, 0xA6, + 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6, 0x68, 0x02, 0x00, 0x33, 0x10, 0x00, 0xB2, 0x88, + 0x76, 0x95, 0x4A, 0x82, 0x42, 0x96, 0x4A, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, + 0x36, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, + 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, + 0x1C, 0x01, 0x02, 0xA6, 0xB0, 0x02, 0x07, 0xA6, 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6, + 0x1A, 0x04, 0x01, 0xA6, 0xBA, 0x02, 0x00, 0xA6, 0xBA, 0x02, 0x00, 0x33, 0x12, 0x00, 0xB2, 0x88, + 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x92, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, + 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, + 0x00, 0x3F, 0x00, 0x00, 0xF0, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE8, 0x02, 0x04, 0x01, + 0x9C, 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xB2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, + 0x70, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x1A, 0x03, 0x00, 0xA6, 0x1A, 0x03, 0x07, 0xA6, 0x12, 0x03, + 0x06, 0xA6, 0x16, 0x03, 0x03, 0xA6, 0x1A, 0x04, 0x02, 0xA6, 0x72, 0x02, 0x00, 0x33, 0x33, 0x00, + 0xB2, 0x88, 0x76, 0x95, 0xF4, 0x82, 0x42, 0x96, 0xF4, 0x82, 0x74, 0x98, 0x80, 0x42, 0x70, 0x98, + 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x5A, 0x03, 0x00, 0x43, + 0x87, 0x01, 0x05, 0x05, 0x78, 0x98, 0x70, 0x98, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x52, 0x03, + 0x03, 0xA6, 0x36, 0x04, 0x06, 0xA6, 0x56, 0x03, 0x01, 0xA6, 0x1C, 0x03, 0x00, 0x33, 0x25, 0x00, + 0xB2, 0x88, 0x76, 0x95, 0x38, 0x83, 0x42, 0x96, 0x38, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, + 0x00, 0x33, 0x42, 0x00, 0xB2, 0x88, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x78, 0x03, 0xB1, 0x01, + 0x08, 0x23, 0xB2, 0x01, 0x34, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x98, 0x03, 0xEC, 0x00, + 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x94, 0x03, 0x00, 0xA6, + 0x94, 0x03, 0x0C, 0x84, 0x80, 0x42, 0x70, 0x98, 0x01, 0xA6, 0xA2, 0x03, 0x00, 0xA6, 0xBA, 0x03, + 0x0C, 0x84, 0x98, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA2, 0x03, 0x07, 0xA6, 0xB0, 0x03, 0xD2, 0x83, + 0x76, 0x95, 0xA6, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xB2, 0x88, 0x98, 0x98, 0x80, 0x42, 0x00, 0xA6, + 0xBA, 0x03, 0x07, 0xA6, 0xC8, 0x03, 0xD2, 0x83, 0x76, 0x95, 0xBE, 0x83, 0x00, 0x33, 0x26, 0x00, + 0xB2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, + 0x0C, 0x84, 0x06, 0xF0, 0x06, 0xA4, 0xF0, 0x03, 0x80, 0x6B, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, + 0x03, 0xA6, 0x0A, 0x04, 0x07, 0xA6, 0x02, 0x04, 0x06, 0xA6, 0x06, 0x04, 0x00, 0x33, 0x17, 0x00, + 0xB2, 0x88, 0x76, 0x95, 0xF0, 0x83, 0x42, 0x96, 0xF0, 0x83, 0x1A, 0x84, 0x06, 0xF0, 0x06, 0xA4, + 0x1A, 0x04, 0x80, 0x6B, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x03, 0xA6, 0x36, 0x04, + 0x07, 0xA6, 0x2E, 0x04, 0x06, 0xA6, 0x32, 0x04, 0x00, 0x33, 0x30, 0x00, 0xB2, 0x88, 0x76, 0x95, + 0x1A, 0x84, 0x42, 0x96, 0x1A, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, + 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x54, 0x04, 0x00, 0x33, + 0x18, 0x00, 0xB2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x5E, 0x04, 0x23, 0x01, + 0x00, 0xA2, 0x80, 0x04, 0x0A, 0xA0, 0x70, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0xB2, 0x88, + 0x0B, 0xA0, 0x7C, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0xB2, 0x88, 0x42, 0x23, 0xE8, 0x88, + 0x00, 0x23, 0x22, 0xA3, 0xE0, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x9C, 0x04, 0x28, 0x23, 0x22, 0xA3, + 0xA8, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xBE, 0x04, 0x42, 0x23, 0xE8, 0x88, 0x4A, 0x00, 0x06, 0x61, + 0x00, 0xA0, 0xA8, 0x04, 0x45, 0x23, 0xE8, 0x88, 0xF6, 0x97, 0x00, 0xA2, 0xBA, 0x04, 0xA4, 0x98, + 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF0, 0x81, 0x47, 0x23, 0xE8, 0x88, 0x04, 0x01, + 0x0B, 0xDE, 0xF6, 0x97, 0xA4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, + 0x00, 0xA0, 0x08, 0x02, 0x43, 0x23, 0xE8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, + 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xEE, 0x04, 0x00, 0x33, 0x27, 0x00, 0xB2, 0x88, 0x04, 0x01, + 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xF6, 0x97, 0x20, 0x95, 0x4B, 0x00, + 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x1C, 0x05, 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, + 0x00, 0xA2, 0x16, 0x05, 0x04, 0x85, 0x38, 0x97, 0xCD, 0x04, 0x1E, 0x85, 0x48, 0x04, 0x84, 0x80, + 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x2E, 0x85, 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x3A, 0x05, 0x1D, 0x01, 0x04, 0xD6, 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, + 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, + 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, + 0xFF, 0xA0, 0x5A, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, + 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xDA, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x88, 0x05, + 0xD6, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xB2, 0x88, 0x04, 0xA0, 0xAE, 0x05, 0x80, 0x63, 0x4A, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x9A, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, + 0x50, 0x00, 0x54, 0x97, 0xFE, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0xFE, 0x84, 0x08, 0xA0, + 0xB4, 0x05, 0xD6, 0x85, 0x03, 0xA0, 0xBA, 0x05, 0xD6, 0x85, 0x01, 0xA0, 0xC4, 0x05, 0x88, 0x00, + 0x80, 0x63, 0xB2, 0x86, 0x07, 0xA0, 0xD0, 0x05, 0x06, 0x23, 0x5A, 0x98, 0x48, 0x23, 0xE8, 0x88, + 0x07, 0x23, 0x80, 0x00, 0xF8, 0x86, 0x80, 0x63, 0x76, 0x85, 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, + 0x00, 0xA2, 0x18, 0x06, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, + 0x06, 0xA6, 0xFA, 0x05, 0x00, 0x33, 0x37, 0x00, 0xB2, 0x88, 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, + 0xE8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x12, 0x06, 0x00, 0x33, 0x38, 0x00, + 0xB2, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x30, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, + 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, + 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x06, 0xA6, 0x5E, 0x06, + 0x07, 0xA6, 0x76, 0x05, 0x02, 0xA6, 0xEC, 0x06, 0x00, 0x33, 0x39, 0x00, 0xB2, 0x88, 0x00, 0x00, + 0x01, 0xA0, 0x06, 0x07, 0xDC, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x72, 0x06, 0x07, 0xA6, + 0x76, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x06, 0x07, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, + 0x06, 0xA6, 0x8E, 0x06, 0x07, 0xA6, 0x76, 0x05, 0x00, 0x33, 0x3A, 0x00, 0xB2, 0x88, 0x40, 0x0E, + 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x80, 0x06, 0x06, 0xA6, 0xA6, 0x06, 0x07, 0xA6, 0x76, 0x05, + 0x00, 0x33, 0x3B, 0x00, 0xB2, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, 0x76, 0x05, + 0x00, 0x63, 0x07, 0xA6, 0xBC, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xB2, 0x88, 0x03, 0x03, 0x80, 0x63, + 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xCE, 0x06, 0x00, 0x33, 0x29, 0x00, 0xB2, 0x88, 0x00, 0x43, + 0x00, 0xA2, 0xDA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xC4, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, + 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x76, 0x85, 0x80, 0x67, 0x00, 0x33, + 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x6A, 0x06, + 0x00, 0x33, 0x2C, 0x00, 0xB2, 0x88, 0x0C, 0xA2, 0x20, 0x07, 0xDC, 0x95, 0x83, 0x03, 0x80, 0x63, + 0x06, 0xA6, 0x1E, 0x07, 0x07, 0xA6, 0x76, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xB2, 0x88, 0x00, 0x00, + 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x36, 0x07, 0x07, 0xA6, 0x76, 0x05, 0xBF, 0x23, + 0x04, 0x61, 0x84, 0x01, 0xE0, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, + 0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05, + 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, + 0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, + 0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00, + 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, + 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, + 0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xB6, 0x07, + 0x00, 0x33, 0x07, 0x00, 0xB2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, + 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, + 0xD6, 0x07, 0x00, 0x05, 0xCC, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05, + 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, + 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, + 0x00, 0xA0, 0x06, 0x08, 0x08, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, + 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, + 0x36, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x16, 0x08, + 0xF6, 0x97, 0x20, 0x95, 0x16, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x4C, 0x88, + 0x02, 0x01, 0x04, 0xD8, 0x38, 0x97, 0xF6, 0x97, 0x20, 0x95, 0x3C, 0x88, 0x75, 0x00, 0x00, 0xA3, + 0x56, 0x08, 0x00, 0x05, 0x40, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, + 0x68, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xB2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, + 0x38, 0x2B, 0x8E, 0x88, 0x38, 0x2B, 0x84, 0x88, 0x32, 0x09, 0x31, 0x05, 0x84, 0x98, 0x05, 0x05, + 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, + 0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, + 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xA4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, + 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, + 0x13, 0x23, 0xE8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, + 0x81, 0x62, 0xD2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, + 0xF1, 0xC7, 0x41, 0x23, 0xE8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE0, 0x84, + }; -STATIC ushort _mcode_size ASC_INITDATA = sizeof(_mcode_buf); -STATIC ulong _mcode_chksum ASC_INITDATA = 0x01297F32UL; +STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf); +STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012A727FUL ; #define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = @@ -8096,6 +11107,7 @@ uchar disable_cmd; ASC_SG_HEAD *sg_head; ulong data_cnt; + iop_base = asc_dvc->iop_base; sg_head = scsiq->sg_head; asc_exe_callback = (ASC_EXE_CALLBACK) asc_dvc->exe_callback; @@ -8146,19 +11158,6 @@ scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); } sg_entry_cnt_minus_one = sg_entry_cnt - 1; -#if CC_DEBUG_SG_LIST - if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { - for (i = 0; i < sg_entry_cnt_minus_one; i++) { - addr = sg_head->sg_list[i].addr + sg_head->sg_list[i].bytes; - if (((ushort) addr & 0x0003) != 0) { - asc_dvc->in_critical_cnt--; - DvcLeaveCritical(last_int_level); - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_LIST_ODD_ADDRESS); - return (ERR); - } - } - } -#endif } scsi_cmd = scsiq->cdbptr[0]; disable_syn_offset_one_fix = FALSE; @@ -8280,6 +11279,7 @@ uchar tid_no; uchar target_ix; int sta; + iop_base = asc_dvc->iop_base; target_ix = scsiq->q2.target_ix; tid_no = ASC_TIX_TO_TID(target_ix); @@ -8294,9 +11294,6 @@ scsiq->q1.q_no = free_q_head; if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq, free_q_head)) == 1) { -#if CC_WRITE_IO_COUNT - asc_dvc->req_count++; -#endif AscPutVarFreeQHead(iop_base, next_qp); asc_dvc->cur_total_qng += (uchar) (n_q_required); asc_dvc->cur_dvc_qng[tid_no]++; @@ -8309,9 +11306,6 @@ scsiq->q1.q_no = free_q_head; if ((sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head)) == 1) { -#if CC_WRITE_IO_COUNT - asc_dvc->req_count++; -#endif AscPutVarFreeQHead(iop_base, next_qp); asc_dvc->cur_total_qng++; asc_dvc->cur_dvc_qng[tid_no]++; @@ -8328,6 +11322,7 @@ ) { int n_sg_list_qs; + n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q); if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0) n_sg_list_qs++; @@ -8346,6 +11341,7 @@ uint cur_free_qs; ASC_SCSI_BIT_ID_TYPE target_id; uchar tid_no; + target_id = ASC_TIX_TO_TARGET_ID(target_ix); tid_no = ASC_TIX_TO_TID(target_ix); if ((asc_dvc->unit_not_ready & target_id) || @@ -8389,6 +11385,7 @@ uchar syn_period_ix; uchar syn_offset; PortAddr iop_base; + iop_base = asc_dvc->iop_base; if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) && ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) { @@ -8410,43 +11407,10 @@ (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), (ushort *) scsiq->cdbptr, (ushort) ((ushort) scsiq->q2.cdb_len >> 1)); -#if !CC_LITTLE_ENDIAN_HOST - AscAdjEndianScsiQ(scsiq); -#endif DvcPutScsiQ(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG), (ushort *) & scsiq->q1.cntl, (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1))); -#if CC_WRITE_IO_COUNT - AscWriteLramWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_W_REQ_COUNT), - (ushort) asc_dvc->req_count); -#endif -#if CC_VERIFY_LRAM_COPY - if ((asc_dvc->dvc_cntl & ASC_CNTL_NO_VERIFY_COPY) == 0) { - if (AscMemWordCmpToLram(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), - (ushort *) scsiq->cdbptr, - (ushort) (scsiq->q2.cdb_len >> 1)) != 0) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM); - return (ERR); - } - if (AscMemWordCmpToLram(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG), - (ushort *) & scsiq->q1.cntl, - (ushort) (((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1)) - != 0) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM); - return (ERR); - } - } -#endif -#if CC_CLEAR_DMA_REMAIN - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_ADDR), 0UL); - AscWriteLramDWord(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT), 0UL); -#endif AscWriteLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY)); @@ -8472,6 +11436,7 @@ ushort sg_entry_cnt; ushort q_addr; uchar next_qp; + iop_base = asc_dvc->iop_base; sg_head = scsiq->sg_head; saved_data_addr = scsiq->q1.data_addr; @@ -8542,6 +11507,7 @@ int sta; ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; PortAddr iop_base; + iop_base = asc_dvc->iop_base; sta = ERR; saved_unit_not_ready = asc_dvc->unit_not_ready; @@ -8571,6 +11537,7 @@ PortAddr iop_base; int sta; uchar tid_no; + ASC_SCSI_BIT_ID_TYPE target_id; int i; ASC_SCSI_REQ_Q scsiq_buf; @@ -8642,13 +11609,14 @@ int sta; int i; PortAddr iop_base; + iop_base = asc_dvc->iop_base; asc_dvc->unit_not_ready = 0xFF; sta = TRUE; AscWaitISRDone(asc_dvc); AscStopQueueExe(iop_base); asc_dvc->sdtr_done = 0; - AscResetChipAndScsiBus(iop_base); + AscResetChipAndScsiBus(asc_dvc); DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); AscReInitLram(asc_dvc); for (i = 0; i <= ASC_MAX_TID; i++) { @@ -8679,6 +11647,7 @@ ) { int sta = FALSE; + if (AscHostReqRiscHalt(iop_base)) { sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); AscStartChip(iop_base); @@ -8696,8 +11665,8 @@ { ASC_SCSI_BIT_ID_TYPE org_id; int i; - int sta; - sta = TRUE; + int sta = TRUE; + AscSetBank(iop_base, 1); org_id = AscReadChipDvcID(iop_base); for (i = 0; i <= ASC_MAX_TID; i++) { @@ -8740,6 +11709,7 @@ ushort s_addr; PortAddr iop_base; ushort warn_code; + iop_base = asc_dvc->iop_base; warn_code = 0; AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0, @@ -8791,6 +11761,7 @@ PortAddr iop_base; int i; ushort lram_addr; + iop_base = asc_dvc->iop_base; AscPutRiscVarFreeQHead(iop_base, 1); AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng); @@ -8840,6 +11811,7 @@ ushort q_addr; uchar q_status; int count = 0; + while (scsiq->q1.q_no == 0) ; q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no); do { @@ -8899,6 +11871,7 @@ { uchar byte; uchar sdtr_period_ix; + sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period); if ( (sdtr_period_ix > asc_dvc->max_sdtr_index) @@ -8931,6 +11904,7 @@ int max_index; int min_index; int i; + period_table = asc_dvc->sdtr_period_tbl; max_index = (int) asc_dvc->max_sdtr_index; min_index = (int)asc_dvc->host_init_sdtr_index ; @@ -8955,6 +11929,7 @@ ushort q_addr; uchar next_qp; uchar q_status; + q_addr = ASC_QNO_TO_QADDR(free_q_head); q_status = (uchar) AscReadLramByte(iop_base, (ushort) (q_addr + ASC_SCSIQ_B_STATUS)); @@ -8974,6 +11949,7 @@ ) { uchar i; + for (i = 0; i < n_free_q; i++) { if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head)) == ASC_QLINK_END) { @@ -8996,6 +11972,7 @@ ASC_QDONE_INFO *scsiq; ASC_ISR_CALLBACK asc_isr_callback; int last_int_level; + iop_base = asc_dvc->iop_base; asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; last_int_level = DvcEnterCritical(); @@ -9041,6 +12018,7 @@ ASC_QDONE_INFO *scsiq; ASC_ISR_CALLBACK asc_isr_callback; int last_int_level; + iop_base = asc_dvc->iop_base; asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; last_int_level = DvcEnterCritical(); @@ -9078,6 +12056,7 @@ int count = 0; int sta = 0; uchar saved_stop_code; + if (AscIsChipHalted(iop_base)) return (1); saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); @@ -9100,8 +12079,8 @@ PortAddr iop_base ) { - int count; - count = 0; + int count = 0; + if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) { AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, ASC_STOP_REQ_RISC_STOP); @@ -9135,6 +12114,7 @@ { int count; uchar stop_code; + count = 0; if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, @@ -9157,6 +12137,7 @@ { int count; uchar stop_code; + count = 0; if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, @@ -9180,12 +12161,14 @@ { uchar cur_req; uchar tid_no; + int i = 0; + tid_no = ASC_TIX_TO_TID(target_ix); - while (TRUE) { + while (i++ < 10) { if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) { break; } - DvcSleepMilliSecond(1000L); + DvcSleepMilliSecond(100L); if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) { break; } @@ -9199,6 +12182,7 @@ ) { int tid; + for (tid = 0; tid <= ASC_MAX_TID; tid++) { AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid)); } @@ -9213,6 +12197,7 @@ ) { ASC_MIN_SG_HEAD sg_head; + sg_head.entry_cnt = ASC_MIN_SG_LIST; if (DvcGetSGList(asc_dvc, (uchar *) buf_addr, buf_size, (ASC_SG_HEAD *) & sg_head) != buf_size) { @@ -9225,20 +12210,15 @@ } STATIC void -DvcDelayNanoSecond( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ulong nano_sec -) +DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec) { - ulong loop; - PortAddr iop_base; - iop_base = asc_dvc->iop_base; - loop = nano_sec / 90; - loop++; - while (loop-- != 0) { - inp(iop_base); - } - return; + udelay(micro_sec); +} + +STATIC void +DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type * asc_dvc, ulong nano_sec) +{ + udelay((nano_sec + 999)/1000); } ASC_INITFUNC( @@ -9251,6 +12231,7 @@ PortAddr eisa_iop; ushort product_id_high, product_id_low; ulong product_id; + eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK; product_id_low = inpw(eisa_iop); product_id_high = inpw(eisa_iop + 2); @@ -9266,6 +12247,7 @@ ) { ulong eisa_product_id; + if (iop_base == 0) { iop_base = ASC_EISA_MIN_IOP_ADDR; } else { @@ -9315,6 +12297,7 @@ ) { uchar cc_val; + cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG)); AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT)); AscSetChipIH(iop_base, INS_HALT); @@ -9358,6 +12341,7 @@ uchar host_flag; uchar risc_flag; ushort loop; + loop = 0; do { risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B); @@ -9386,6 +12370,7 @@ ) { ushort cfg; + cfg = AscGetChipCfgLsw(iop_base); AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON)); return; @@ -9397,6 +12382,7 @@ ) { ushort cfg; + cfg = AscGetChipCfgLsw(iop_base); AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON); return; @@ -9411,6 +12397,7 @@ ) { uchar val; + val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET)); if (bank == 1) { @@ -9424,17 +12411,18 @@ return; } - - STATIC int AscResetChipAndScsiBus( - PortAddr iop_base + ASC_DVC_VAR *asc_dvc ) { + PortAddr iop_base; + + iop_base = asc_dvc->iop_base; while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ; AscStopChip(iop_base); AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT); - DvcSleepMilliSecond(200); + DvcDelayNanoSecond(asc_dvc, 60000); AscSetChipIH(iop_base, INS_RFLAG_WTM); AscSetChipIH(iop_base, INS_HALT); AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT); @@ -9467,6 +12455,7 @@ ) { ushort channel; + channel = AscGetChipCfgLsw(iop_base) & 0x0003; if (channel == 0x03) return (0); @@ -9485,6 +12474,7 @@ { ushort cfg_lsw; uchar value; + if ((dma_channel >= 5) && (dma_channel <= 7)) { if (dma_channel == 7) value = 0x00; @@ -9521,6 +12511,7 @@ ) { uchar speed_value; + AscSetBank(iop_base, 1); speed_value = AscReadChipDmaSpeed(iop_base); speed_value &= 0x07; @@ -9634,8 +12625,8 @@ ) ) { - ushort warn_code; - warn_code = 0; + ushort warn_code = 0; + asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG; if (asc_dvc->err_code != 0) return (UW_ERR); @@ -9659,6 +12650,7 @@ ushort cfg_msw; ushort warn_code; ushort pci_device_id; + iop_base = asc_dvc->iop_base; pci_device_id = asc_dvc->cfg->pci_device_id; warn_code = 0; @@ -9683,10 +12675,8 @@ } } if (asc_dvc->bus_type & ASC_IS_PCI) { -#if CC_DISABLE_PCI_PARITY_INT cfg_msw &= 0xFFC0; AscSetChipCfgMsw(iop_base, cfg_msw); -#endif if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) { } else { if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) || @@ -9721,14 +12711,15 @@ { ushort warn_code; PortAddr iop_base; - extern ushort _mcode_size; - extern ulong _mcode_chksum; - extern uchar _mcode_buf[]; + extern ushort _asc_mcode_size; + extern ulong _asc_mcode_chksum; + extern uchar _asc_mcode_buf[]; + iop_base = asc_dvc->iop_base; warn_code = 0; if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) && !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) { - AscResetChipAndScsiBus(iop_base); + AscResetChipAndScsiBus(asc_dvc); DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); } asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC; @@ -9742,8 +12733,8 @@ warn_code |= AscInitLram(asc_dvc); if (asc_dvc->err_code != 0) return (UW_ERR); - if (AscLoadMicroCode(iop_base, 0, (ushort *) _mcode_buf, - _mcode_size) != _mcode_chksum) { + if (AscLoadMicroCode(iop_base, 0, (ushort *) _asc_mcode_buf, + _asc_mcode_size) != _asc_mcode_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return (warn_code); } @@ -9764,6 +12755,7 @@ PortAddr iop_base; ushort warn_code; uchar chip_version; + iop_base = asc_dvc->iop_base; warn_code = 0; asc_dvc->err_code = 0; @@ -9866,7 +12858,6 @@ return (warn_code); } -#if CC_INCLUDE_EEP_CONFIG ASC_INITFUNC( STATIC ushort AscInitFromEEP( @@ -9875,12 +12866,14 @@ ) { ASCEEP_CONFIG eep_config_buf; - ASCEEP_CONFIG *eep_config; + ASCEEP_CONFIG *eep_config; PortAddr iop_base; ushort chksum; ushort warn_code; ushort cfg_msw, cfg_lsw; int i; + int write_eep = 0; + iop_base = asc_dvc->iop_base; warn_code = 0; AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE); @@ -9888,7 +12881,7 @@ if ((AscStopChip(iop_base) == FALSE) || (AscGetChipScsiCtrl(iop_base) != 0)) { asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE; - AscResetChipAndScsiBus(iop_base); + AscResetChipAndScsiBus(asc_dvc); DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); } if (AscIsChipHalted(iop_base) == FALSE) { @@ -9909,7 +12902,9 @@ AscSetChipCfgMsw(iop_base, cfg_msw); } chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); - eep_config->cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); + if (chksum == 0) { + chksum = 0xaa55; + } if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { warn_code |= ASC_WARN_AUTO_CONFIG; if (asc_dvc->cfg->chip_version == 3) { @@ -9923,9 +12918,32 @@ } } } + eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; if (chksum != eep_config->chksum) { - warn_code |= ASC_WARN_EEPROM_CHKSUM; + if (AscGetChipVersion(iop_base, asc_dvc->bus_type) == + ASC_CHIP_VER_PCI_ULTRA_3050 ) + { + eep_config->init_sdtr = 0xFF; + eep_config->disc_enable = 0xFF; + eep_config->start_motor = 0xFF; + eep_config->use_cmd_qng = 0; + eep_config->max_total_qng = 0xF0; + eep_config->max_tag_qng = 0x20; + eep_config->cntl = 0xBFFF; + eep_config->chip_scsi_id = 7; + eep_config->no_scam = 0; + eep_config->adapter_info[0] = 0; + eep_config->adapter_info[1] = 0; + eep_config->adapter_info[2] = 0; + eep_config->adapter_info[3] = 0; + eep_config->adapter_info[4] = 0; + /* Indicate EEPROM-less board. */ + eep_config->adapter_info[5] = 0xBB; + } else { + write_eep = 1 ; + warn_code |= ASC_WARN_EEPROM_CHKSUM ; + } } asc_dvc->init_sdtr = eep_config->init_sdtr; asc_dvc->cfg->disc_enable = eep_config->disc_enable; @@ -9934,6 +12952,12 @@ asc_dvc->start_motor = eep_config->start_motor; asc_dvc->dvc_cntl = eep_config->cntl; asc_dvc->no_scam = eep_config->no_scam; + asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0]; + asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1]; + asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2]; + asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3]; + asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4]; + asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5]; if (!AscTestExternalLram(asc_dvc)) { if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) { eep_config->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG; @@ -9976,9 +13000,6 @@ } for (i = 0; i <= ASC_MAX_TID; i++) { -#if CC_TMP_USE_EEP_SDTR - asc_dvc->cfg->sdtr_period_offset[i] = eep_config->dos_int13_table[i]; -#endif asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i]; asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng; asc_dvc->cfg->sdtr_period_offset[i] = @@ -9986,14 +13007,11 @@ (asc_dvc->host_init_sdtr_index << 4)); } eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); -#if CC_CHK_FIX_EEP_CONTENT - if (AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type) != 0) { - asc_dvc->err_code |= ASC_IERR_WRITE_EEPROM; + if (write_eep) { + (void) AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); } -#endif return (warn_code); } -#endif ASC_INITFUNC( STATIC ushort @@ -10006,6 +13024,7 @@ ushort warn_code; PortAddr iop_base; ulong phy_addr; + iop_base = asc_dvc->iop_base; warn_code = 0; for (i = 0; i <= ASC_MAX_TID; i++) { @@ -10054,6 +13073,7 @@ ASC_ISR_CALLBACK asc_isr_callback; uchar cp_sen_len; uchar i; + ASC_DBG(1, "AscInitPollIsrCallBack: begin\n"); if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) { scsiq_req = (ASC_SCSI_REQ_Q *) scsi_done_q->d2.srb_ptr; @@ -10095,6 +13115,7 @@ ushort q_addr; ushort saved_word; int sta; + iop_base = asc_dvc->iop_base; sta = 0; q_addr = ASC_QNO_TO_QADDR(241); @@ -10110,7 +13131,6 @@ return (sta); } -#if CC_INCLUDE_EEP_CONFIG ASC_INITFUNC( STATIC int AscWriteEEPCmdReg( @@ -10121,6 +13141,7 @@ { uchar read_back; int retry; + retry = 0; while (TRUE) { AscSetChipEEPCmd(iop_base, cmd_reg); @@ -10145,6 +13166,7 @@ { ushort read_back; int retry; + retry = 0; while (TRUE) { AscSetChipEEPData(iop_base, data_reg); @@ -10191,6 +13213,7 @@ { ushort read_wval; uchar cmd_reg; + AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); AscWaitEEPRead(); cmd_reg = addr | ASC_EEP_CMD_READ; @@ -10211,6 +13234,7 @@ ) { ushort read_wval; + read_wval = AscReadEEPWord(iop_base, addr); if (read_wval != word_val) { AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE); @@ -10242,6 +13266,7 @@ int cfg_end; int s_addr; int isa_pnp_wsize; + wbuf = (ushort *) cfg_buf; sum = 0; isa_pnp_wsize = 0; @@ -10267,7 +13292,6 @@ return (sum); } -#if CC_CHK_FIX_EEP_CONTENT ASC_INITFUNC( STATIC int AscSetEEPConfigOnce( @@ -10282,6 +13306,7 @@ int s_addr; int cfg_beg; int cfg_end; + wbuf = (ushort *) cfg_buf; n_error = 0; sum = 0; @@ -10347,8 +13372,6 @@ } return (n_error); } -#endif -#endif STATIC int AscInitPollBegin( @@ -10356,6 +13379,7 @@ ) { PortAddr iop_base; + iop_base = asc_dvc->iop_base; AscDisableInterrupt(iop_base); asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY; @@ -10374,6 +13398,7 @@ { PortAddr iop_base; rint i; + iop_base = asc_dvc->iop_base; asc_dvc->isr_callback = (Ptr2Func) asc_dvc->saved_ptr2func; AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, @@ -10393,8 +13418,6 @@ return (0); } -STATIC int _asc_wait_slow_device_ = FALSE; - STATIC int AscInitPollTarget( REG ASC_DVC_VAR asc_ptr_type * asc_dvc, @@ -10425,9 +13448,9 @@ if (PollScsiInquiry(asc_dvc, scsiq, (uchar *) inq, sizeof (ASC_SCSI_INQUIRY)) == 1) { dvc_found = 1; - support_read_cap = TRUE; dvc_type = inq->byte0.peri_dvc_type; if (dvc_type != SCSI_TYPE_UNKNOWN) { + support_read_cap = TRUE; if ((dvc_type != SCSI_TYPE_DASD) && (dvc_type != SCSI_TYPE_WORM) && (dvc_type != SCSI_TYPE_CDROM) @@ -10435,12 +13458,6 @@ asc_dvc->start_motor &= ~tid_bits; support_read_cap = FALSE; } - if ((dvc_type != SCSI_TYPE_DASD) || inq->byte1.rmb) { - if (!_asc_wait_slow_device_) { - DvcSleepMilliSecond(3000 - ((int) tid_no * 250)); - _asc_wait_slow_device_ = TRUE; - } - } if (lun == 0) { if ((inq->byte3.rsp_data_fmt >= 2) || (inq->byte2.ansi_apr_ver >= 2)) { @@ -10494,6 +13511,14 @@ (uchar *)"CD-ROM DRIVE ", 16) == 0)) { asc_dvc->pci_fix_asyn_xfer &= ~tid_bits ; } + if ((dvc_type == SCSI_TYPE_CDROM) && + (AscCompareString((uchar *) inq->vendor_id, + (uchar *) "YAMAHA", 6) == 0) && + (AscCompareString((uchar *) inq->product_id, + (uchar *) "CDR400", 6) == 0)) + { + asc_dvc->pci_fix_asyn_xfer &= ~tid_bits ; + } if (asc_dvc->pci_fix_asyn_xfer & tid_bits) { AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no, @@ -10553,7 +13578,7 @@ scsiq->r3.host_stat = 0; scsiq->r3.scsi_stat = 0; scsiq->r3.scsi_msg = 0; - DvcSleepMilliSecond(2000); + DvcSleepMilliSecond(1000); continue; } scsiq->r3.done_stat = 0; @@ -10611,19 +13636,15 @@ { ASC_CAP_INFO scsi_cap_info; int status; + if (AscScsiReadCapacity(asc_dvc, scsiq, (uchar *) & scsi_cap_info) == ERR) { return (scsiq->r3.done_stat = QD_WITH_ERROR); } status = PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 8); if (status == 1) { -#if CC_LITTLE_ENDIAN_HOST cap_info->lba = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.lba); cap_info->blk_size = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.blk_size); -#else - cap_info->lba = scsi_cap_info.lba; - cap_info->blk_size = scsi_cap_info.blk_size; -#endif return (scsiq->r3.done_stat); } return (scsiq->r3.done_stat = QD_WITH_ERROR); @@ -10668,6 +13689,7 @@ ASC_SCSI_BIT_ID_TYPE tid_bits; int retry; ASC_REQ_SENSE *sen; + retry = 0; tid_bits = scsiq->r1.target_id; while (retry++ < 4) { @@ -10675,26 +13697,28 @@ if (scsiq->r3.done_stat == 0x01) { return (1); } else if (scsiq->r3.done_stat == QD_WITH_ERROR) { - DvcSleepMilliSecond(200); sen = (ASC_REQ_SENSE *) scsiq->sense_ptr; if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) && ((sen->err_code & 0x70) != 0)) { if (sen->sense_key == SCSI_SENKEY_NOT_READY) { + if (sen->asc == SCSI_ASC_NOMEDIA) + { + break; + } if (asc_dvc->start_motor & tid_bits) { if (PollScsiStartUnit(asc_dvc, scsiq) == 1) { - retry = 0; + DvcSleepMilliSecond(250); continue; } else { asc_dvc->start_motor &= ~tid_bits; break; } } else { - DvcSleepMilliSecond(5000); + DvcSleepMilliSecond(250); } } else if (sen->sense_key == SCSI_SENKEY_ATTENTION) { - DvcSleepMilliSecond((ulong)(500L*retry)) ; + DvcSleepMilliSecond(250); } else { - DvcSleepMilliSecond(500) ; break; } } else { @@ -10719,6 +13743,7 @@ int loop, loop_end; int sta; PortAddr iop_base; + iop_base = asc_dvc->iop_base; loop = 0; loop_end = timeout_sec * 100; @@ -10745,17 +13770,11 @@ } if (AscIsChipHalted(iop_base)) { ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n"); -#if !CC_ASCISR_CHECK_INT_PENDING - AscAckInterrupt(iop_base); -#endif AscISR(asc_dvc); loop = 0; } else { if (AscIsIntPending(iop_base)) { ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n"); -#if !CC_ASCISR_CHECK_INT_PENDING - AscAckInterrupt(iop_base); -#endif AscISR(asc_dvc); } } @@ -10772,6 +13791,7 @@ { int i; int diff; + for (i = 0; i < len; i++) { diff = (int) (str1[i] - str2[i]); if (diff != 0) @@ -10788,6 +13808,7 @@ { uchar byte_data; ushort word_data; + if (isodd_word(addr)) { AscSetChipLramAddr(iop_base, addr - 1); word_data = AscGetChipLramData(iop_base); @@ -10807,6 +13828,7 @@ ) { ushort word_data; + AscSetChipLramAddr(iop_base, addr); word_data = AscGetChipLramData(iop_base); return (word_data); @@ -10820,6 +13842,7 @@ { ushort val_low, val_high; ulong dword_data; + AscSetChipLramAddr(iop_base, addr); val_low = AscGetChipLramData(iop_base); val_high = AscGetChipLramData(iop_base); @@ -10847,6 +13870,7 @@ ) { ushort word_val; + AscSetChipLramAddr(iop_base, addr); word_val = (ushort) dword_val; AscSetChipLramData(iop_base, word_val); @@ -10863,6 +13887,7 @@ ) { ushort word_data; + if (isodd_word(addr)) { addr--; word_data = AscReadLramWord(iop_base, addr); @@ -10925,6 +13950,7 @@ { ulong sum; int i; + sum = 0L; for (i = 0; i < words; i++, s_addr += 2) { sum += AscReadLramWord(iop_base, s_addr); @@ -10941,6 +13967,7 @@ ) { rint i; + AscSetChipLramAddr(iop_base, s_addr); for (i = 0; i < words; i++) { AscSetChipLramData(iop_base, set_wval); @@ -11035,4 +14062,1728 @@ scsiq->cdb[5] = 0; scsiq->r2.cdb_len = 6; return (0); +} + + +/* + * --- Adv Library Functions + */ + +/* a_qswap.h */ +STATIC unsigned char _adv_mcode_buf[] ASC_INITDATA = { + 0x9C, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0x40, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x01, 0xD2, 0x11, 0x00, 0x00, 0x70, 0x01, + 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x0F, 0x22, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xF7, 0x70, 0x01, 0x0C, 0x1C, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF2, 0xD2, 0x0A, + 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x3E, 0x57, 0x3C, 0x56, 0x0C, 0x1C, 0x00, 0xFC, + 0xA6, 0x00, 0x01, 0x58, 0xAA, 0x13, 0x20, 0xF0, 0x9A, 0x03, 0x06, 0xEC, 0xB9, 0x00, 0x0E, 0x47, + 0x03, 0xE6, 0x10, 0x00, 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0x06, 0xEA, 0xB9, 0x00, 0x47, 0x4B, + 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x4E, 0x12, 0x03, 0xF6, 0xC0, 0x00, + 0x00, 0xF2, 0x64, 0x0A, 0x41, 0x58, 0x03, 0xF6, 0xD0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x49, 0x44, + 0x59, 0xF0, 0x0A, 0x02, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x44, 0x58, 0x00, 0xF2, + 0xDE, 0x0D, 0x02, 0xCC, 0x4A, 0xE4, 0x01, 0x00, 0x55, 0xF0, 0x08, 0x03, 0x45, 0xF4, 0x02, 0x00, + 0x83, 0x5A, 0x04, 0xCC, 0x01, 0x4A, 0x12, 0x12, 0x00, 0xF2, 0xDE, 0x0D, 0x00, 0xCD, 0x48, 0xE4, + 0x01, 0x00, 0xE9, 0x13, 0x00, 0xF2, 0xC2, 0x0F, 0xFA, 0x10, 0x0E, 0x47, 0x03, 0xE6, 0x10, 0x00, + 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0xCE, 0x47, 0x97, 0x13, 0x04, 0xEC, 0xB4, 0x00, 0x00, 0xF2, + 0xDE, 0x0D, 0x00, 0xCD, 0x48, 0xE4, 0x00, 0x00, 0x12, 0x12, 0x3E, 0x57, 0x06, 0xCC, 0x45, 0xF4, + 0x02, 0x00, 0x83, 0x5A, 0x00, 0xCC, 0x00, 0xEA, 0xB4, 0x00, 0x92, 0x10, 0x00, 0xF0, 0x8C, 0x01, + 0x43, 0xF0, 0x5C, 0x02, 0x44, 0xF0, 0x60, 0x02, 0x45, 0xF0, 0x64, 0x02, 0x46, 0xF0, 0x68, 0x02, + 0x47, 0xF0, 0x6E, 0x02, 0x48, 0xF0, 0x9E, 0x02, 0xB9, 0x54, 0x62, 0x10, 0x00, 0x1C, 0x5A, 0x10, + 0x02, 0x1C, 0x56, 0x10, 0x1E, 0x1C, 0x52, 0x10, 0x00, 0xF2, 0x1A, 0x11, 0x50, 0x10, 0x06, 0xFC, + 0xA8, 0x00, 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x4A, 0x0A, 0x8C, 0x10, 0x01, 0xF6, 0x01, 0x00, + 0x01, 0xFA, 0xA8, 0x00, 0x00, 0xF2, 0x28, 0x0B, 0x06, 0x10, 0xB9, 0x54, 0x01, 0xFA, 0xA8, 0x00, + 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x54, 0x0A, 0x01, 0xFC, 0xA8, 0x00, 0x20, 0x10, 0x58, 0x1C, + 0x00, 0xF2, 0x18, 0x0B, 0x5A, 0x1C, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54, 0x00, 0xFA, 0xA6, 0x00, + 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x72, 0x01, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54, + 0x00, 0xFA, 0xA6, 0x00, 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x80, 0x01, 0x03, 0xF6, + 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x0A, 0x13, 0x00, 0xF2, 0x34, 0x10, 0x00, 0xF2, + 0x50, 0x0F, 0x24, 0x10, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x02, 0xF6, 0xD0, 0x00, + 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x49, 0x44, 0x5B, 0xF0, 0x04, 0x03, 0x00, 0xF2, 0x98, 0x0F, + 0x00, 0xF0, 0x80, 0x01, 0x00, 0xF2, 0x10, 0x10, 0x0C, 0x1C, 0x02, 0x4B, 0xBF, 0x57, 0x9E, 0x43, + 0x77, 0x57, 0x07, 0x4B, 0x20, 0xF0, 0x9A, 0x03, 0x40, 0x1C, 0x1E, 0xF0, 0x30, 0x03, 0x26, 0xF0, + 0x2C, 0x03, 0xA0, 0xF0, 0x1A, 0x03, 0x11, 0xF0, 0x9A, 0x03, 0x12, 0x10, 0x9F, 0xF0, 0x3E, 0x03, + 0x46, 0x1C, 0x82, 0xE7, 0x05, 0x00, 0x9E, 0xE7, 0x11, 0x00, 0x00, 0xF0, 0x02, 0x0A, 0x0C, 0x1C, + 0x48, 0x1C, 0x46, 0x1C, 0x38, 0x54, 0x00, 0xEC, 0xBA, 0x00, 0x08, 0x44, 0x00, 0xEA, 0xBA, 0x00, + 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x08, 0x44, 0x00, 0x4C, 0x82, 0xE7, 0x02, 0x00, + 0x00, 0xF2, 0x0E, 0x11, 0x00, 0xF2, 0x0E, 0x11, 0x06, 0xF0, 0x74, 0x03, 0x1E, 0xF0, 0xF8, 0x09, + 0x00, 0xF0, 0xFE, 0x09, 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0x55, 0xF0, 0xA0, 0x04, 0x01, 0xE6, + 0x0C, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, + 0xC4, 0x11, 0x01, 0xF0, 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x46, 0x1C, 0x0C, 0x1C, 0x67, 0x1B, + 0xBF, 0x57, 0x77, 0x57, 0x02, 0x4B, 0x48, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x8E, 0x0D, 0x30, 0x1C, + 0x96, 0xF0, 0xB0, 0x03, 0xB1, 0xF0, 0xB4, 0x03, 0x1E, 0xF0, 0xF8, 0x09, 0x85, 0xF0, 0xFE, 0x09, + 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0x14, 0x12, 0x01, 0xE6, 0x0C, 0x00, 0x00, 0xF2, 0x4A, 0x0D, + 0x00, 0xF2, 0x0E, 0x11, 0x01, 0xF0, 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x03, 0xF6, 0xE0, 0x00, + 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x55, 0xF0, 0x8C, 0x04, 0x03, 0x82, 0x03, 0xFC, 0xA0, 0x00, + 0x9B, 0x57, 0x40, 0x12, 0x69, 0x18, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0x36, 0x04, 0x69, 0x08, + 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0xFE, 0x09, 0x68, 0x08, 0x4C, 0x44, 0x28, 0x12, 0x44, 0x48, + 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x45, 0x58, 0x00, 0xF2, 0xF2, 0x0D, 0x00, 0xCC, + 0x01, 0x48, 0x55, 0xF0, 0x8C, 0x04, 0x4C, 0x44, 0xEF, 0x13, 0x00, 0xF2, 0xC2, 0x0F, 0x00, 0xF2, + 0x10, 0x10, 0x08, 0x10, 0x68, 0x18, 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, 0x04, 0x80, 0x18, 0xE4, + 0x10, 0x00, 0x28, 0x12, 0x01, 0xE6, 0x06, 0x00, 0x04, 0x80, 0x18, 0xE4, 0x01, 0x00, 0x04, 0x12, + 0x01, 0xE6, 0x0D, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x04, 0xE6, 0x02, 0x00, + 0x9E, 0xE7, 0x15, 0x00, 0x01, 0xF0, 0x18, 0x0A, 0x00, 0xF0, 0xFE, 0x09, 0x69, 0x08, 0x05, 0x80, + 0x48, 0xE4, 0x00, 0x00, 0x0C, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, 0xB8, 0x00, 0x00, 0xF2, + 0xB2, 0x10, 0x82, 0xE7, 0x02, 0x00, 0x1C, 0x90, 0x40, 0x5C, 0x00, 0x16, 0x01, 0xE6, 0x06, 0x00, + 0x00, 0xF2, 0x4A, 0x0D, 0x01, 0xF0, 0x80, 0x01, 0x1E, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0x94, 0x04, + 0x42, 0x5B, 0x06, 0xF7, 0x03, 0x00, 0x46, 0x59, 0xBF, 0x57, 0x77, 0x57, 0x01, 0xE6, 0x80, 0x00, + 0x07, 0x80, 0x31, 0x44, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x5E, 0x13, 0x20, 0x80, 0x48, 0xE4, + 0x03, 0x00, 0x56, 0x12, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x4C, 0x13, 0x00, 0xFC, 0xA2, 0x00, + 0x98, 0x57, 0x55, 0xF0, 0x18, 0x05, 0x31, 0xE4, 0x40, 0x00, 0x00, 0xFC, 0xA0, 0x00, 0x98, 0x57, + 0x36, 0x12, 0x4C, 0x1C, 0x00, 0xF2, 0x0E, 0x11, 0x89, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, + 0x2A, 0x05, 0x82, 0xE7, 0x06, 0x00, 0x1B, 0x80, 0x48, 0xE4, 0x22, 0x00, 0x5B, 0xF0, 0x08, 0x05, + 0x48, 0xE4, 0x20, 0x00, 0x59, 0xF0, 0x0C, 0x05, 0x00, 0xE6, 0x20, 0x00, 0x09, 0x48, 0x00, 0xF2, + 0x0E, 0x11, 0x86, 0xF0, 0x2A, 0x05, 0x83, 0x80, 0x04, 0x10, 0x00, 0xF2, 0x9E, 0x0D, 0x00, 0xE6, + 0x01, 0x00, 0x00, 0xEA, 0x26, 0x01, 0x01, 0xEA, 0x27, 0x01, 0x04, 0x80, 0x18, 0xE4, 0x10, 0x00, + 0x36, 0x12, 0xB9, 0x54, 0x00, 0xF2, 0xF2, 0x0E, 0x01, 0xE6, 0x06, 0x00, 0x04, 0x80, 0x18, 0xE4, + 0x01, 0x00, 0x04, 0x12, 0x01, 0xE6, 0x0D, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, + 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, + 0x01, 0xF0, 0x18, 0x0A, 0x00, 0xF0, 0xFE, 0x09, 0x00, 0xFC, 0x20, 0x01, 0x98, 0x57, 0x34, 0x12, + 0x00, 0xFC, 0x24, 0x01, 0x98, 0x57, 0x2C, 0x13, 0xB9, 0x54, 0x00, 0xF2, 0xF2, 0x0E, 0x86, 0xF0, + 0xA4, 0x05, 0x03, 0xF6, 0x01, 0x00, 0x00, 0xF2, 0x88, 0x0E, 0x85, 0xF0, 0x9A, 0x05, 0x82, 0xE7, + 0x03, 0x00, 0x00, 0xF2, 0x5C, 0x0B, 0x82, 0xE7, 0x02, 0x00, 0x00, 0xFC, 0x24, 0x01, 0xB0, 0x57, + 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFC, 0x9E, 0x00, 0x98, 0x57, 0x5A, 0x12, 0x00, 0xFC, 0xB6, 0x00, + 0x98, 0x57, 0x52, 0x13, 0x03, 0xE6, 0x0C, 0x00, 0x00, 0xFC, 0x9C, 0x00, 0x98, 0x57, 0x04, 0x13, + 0x03, 0xE6, 0x19, 0x00, 0x05, 0xE6, 0x08, 0x00, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, + 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x04, 0x13, 0x05, 0xE6, 0x0F, 0x00, 0xB9, 0x54, + 0x00, 0xF2, 0xF2, 0x0E, 0x86, 0xF0, 0x06, 0x06, 0x00, 0xF2, 0xB6, 0x0E, 0x85, 0xF0, 0xFC, 0x05, + 0x82, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x5C, 0x0B, 0x82, 0xE7, 0x02, 0x00, 0x00, 0xFC, 0xB6, 0x00, + 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0xF2, 0xF2, 0x0E, 0x9C, 0x32, + 0x4E, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x8E, 0x0D, 0x30, 0x1C, 0x82, 0xE7, 0x04, 0x00, 0xB1, 0xF0, + 0x1E, 0x06, 0x0A, 0xF0, 0x3A, 0x06, 0x05, 0xF0, 0xD2, 0x06, 0x06, 0xF0, 0xD8, 0x06, 0x09, 0xF0, + 0x20, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0x00, 0xF0, 0xFE, 0x09, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, + 0x30, 0x12, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x21, 0x80, 0x18, 0xE4, 0xE0, 0x00, + 0x09, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, + 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x99, 0xA4, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, + 0x9A, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x34, 0x12, 0x09, 0xE7, 0x1B, 0x00, 0x00, 0xF2, + 0x0E, 0x11, 0x21, 0x80, 0x18, 0xE4, 0xE0, 0x00, 0x09, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, + 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, + 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF0, 0x08, 0x09, 0xBB, 0x55, + 0x9A, 0x81, 0x03, 0xF7, 0x20, 0x00, 0x09, 0x6F, 0x93, 0x45, 0x55, 0xF0, 0xDE, 0x06, 0xB1, 0xF0, + 0xBE, 0x06, 0x0A, 0xF0, 0xB6, 0x06, 0x09, 0xF0, 0x20, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0x00, 0xF0, + 0xFE, 0x09, 0x00, 0xF2, 0x5C, 0x0B, 0x47, 0x10, 0x09, 0xE7, 0x08, 0x00, 0x41, 0x10, 0x05, 0x80, + 0x48, 0xE4, 0x00, 0x00, 0x1E, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, 0xB8, 0x00, 0x00, 0xF2, + 0xB2, 0x10, 0x2C, 0x90, 0xAE, 0x90, 0x08, 0x50, 0x8A, 0x50, 0x38, 0x54, 0x1F, 0x40, 0x00, 0xF2, + 0xB0, 0x0D, 0x08, 0x10, 0x08, 0x90, 0x8A, 0x90, 0x30, 0x50, 0xB2, 0x50, 0x9C, 0x32, 0x0C, 0x92, + 0x8E, 0x92, 0x38, 0x54, 0x04, 0x80, 0x30, 0xE4, 0x08, 0x00, 0x04, 0x40, 0x0C, 0x1C, 0x00, 0xF6, + 0x03, 0x00, 0xB1, 0xF0, 0x22, 0x07, 0x9E, 0xF0, 0x36, 0x07, 0x01, 0x48, 0x55, 0xF0, 0xF8, 0x09, + 0x0C, 0x1C, 0x10, 0x44, 0xED, 0x10, 0x0B, 0xF0, 0x5A, 0x07, 0x0C, 0xF0, 0x5E, 0x07, 0x05, 0xF0, + 0x4E, 0x07, 0x06, 0xF0, 0x54, 0x07, 0x09, 0xF0, 0x20, 0x09, 0x00, 0xF0, 0xFE, 0x09, 0x00, 0xF2, + 0x5C, 0x0B, 0xCF, 0x10, 0x09, 0xE7, 0x08, 0x00, 0xC9, 0x10, 0x2E, 0x1C, 0x02, 0x10, 0x2C, 0x1C, + 0xAA, 0xF0, 0x60, 0x07, 0xAC, 0xF0, 0x6E, 0x07, 0x40, 0x10, 0x34, 0x1C, 0xF3, 0x10, 0xAD, 0xF0, + 0x78, 0x07, 0xC8, 0x10, 0x36, 0x1C, 0xE9, 0x10, 0x2B, 0xF0, 0x7E, 0x08, 0x6B, 0x18, 0x18, 0xF4, + 0x00, 0xFE, 0x20, 0x12, 0x01, 0x58, 0xD2, 0xF0, 0x7E, 0x08, 0x76, 0x18, 0x18, 0xF4, 0x03, 0x00, + 0xEC, 0x12, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xE2, 0x12, 0x0B, 0xF0, 0x60, 0x07, + 0x0C, 0xF0, 0x60, 0x07, 0x36, 0x1C, 0x34, 0x1C, 0xB7, 0x10, 0x38, 0x54, 0xB9, 0x54, 0x84, 0x80, + 0x19, 0xE4, 0x20, 0x00, 0xB2, 0x13, 0x85, 0x80, 0x81, 0x48, 0x66, 0x12, 0x04, 0x80, 0x18, 0xE4, + 0x08, 0x00, 0x58, 0x13, 0x1F, 0x80, 0x08, 0x44, 0xC8, 0x44, 0x9F, 0x12, 0x1F, 0x40, 0x34, 0x91, + 0xB6, 0x91, 0x44, 0x55, 0xE5, 0x55, 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, 0xBB, 0x55, 0x82, 0x81, + 0xC0, 0x55, 0x48, 0xF4, 0x0F, 0x00, 0x5A, 0xF0, 0x16, 0x08, 0x4A, 0xE4, 0x17, 0x00, 0xD5, 0xF0, + 0xF6, 0x07, 0x02, 0xF6, 0x0F, 0x00, 0x02, 0xF4, 0x02, 0x00, 0x02, 0xEA, 0xB8, 0x00, 0x04, 0x91, + 0x86, 0x91, 0x02, 0x4B, 0x2C, 0x90, 0x08, 0x50, 0x2E, 0x90, 0x0A, 0x50, 0x2C, 0x51, 0xAE, 0x51, + 0x00, 0xF2, 0xB2, 0x10, 0x38, 0x54, 0x00, 0xF2, 0xB0, 0x0D, 0x56, 0x10, 0x34, 0x91, 0xB6, 0x91, + 0x0C, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x08, 0x00, 0x41, 0x12, 0x0C, 0x91, 0x8E, 0x91, 0x04, 0x80, + 0x18, 0xE4, 0xF7, 0x00, 0x04, 0x40, 0x30, 0x90, 0xB2, 0x90, 0x36, 0x10, 0x02, 0x80, 0x48, 0xE4, + 0x10, 0x00, 0x31, 0x12, 0x82, 0xE7, 0x10, 0x00, 0x84, 0x80, 0x19, 0xE4, 0x20, 0x00, 0x10, 0x13, + 0x0C, 0x90, 0x8E, 0x90, 0x5D, 0xF0, 0x74, 0x07, 0x0C, 0x58, 0x8D, 0x58, 0x00, 0xF0, 0x60, 0x07, + 0x38, 0x54, 0xB9, 0x54, 0x19, 0x80, 0xF1, 0x10, 0x3A, 0x55, 0x19, 0x81, 0xBB, 0x55, 0x10, 0x90, + 0x92, 0x90, 0x10, 0x58, 0x91, 0x58, 0x14, 0x59, 0x95, 0x59, 0x00, 0xF0, 0x60, 0x07, 0x04, 0x80, + 0x18, 0xE4, 0x20, 0x00, 0x06, 0x12, 0x6C, 0x19, 0x19, 0x41, 0x7C, 0x10, 0x6C, 0x19, 0x0C, 0x51, + 0xED, 0x19, 0x8E, 0x51, 0x6B, 0x18, 0x18, 0xF4, 0x00, 0xFF, 0x02, 0x13, 0x6A, 0x10, 0x01, 0x58, + 0xD2, 0xF0, 0xBC, 0x08, 0x76, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x0A, 0x12, 0x00, 0xFC, 0x22, 0x01, + 0x18, 0xF4, 0x01, 0x00, 0x06, 0x13, 0x9E, 0xE7, 0x16, 0x00, 0x4C, 0x10, 0xD1, 0xF0, 0xC6, 0x08, + 0x9E, 0xE7, 0x17, 0x00, 0x42, 0x10, 0xD0, 0xF0, 0xD0, 0x08, 0x9E, 0xE7, 0x19, 0x00, 0x38, 0x10, + 0xCF, 0xF0, 0xDA, 0x08, 0x9E, 0xE7, 0x20, 0x00, 0x2E, 0x10, 0xCE, 0xF0, 0xE4, 0x08, 0x9E, 0xE7, + 0x21, 0x00, 0x24, 0x10, 0xCD, 0xF0, 0xEE, 0x08, 0x9E, 0xE7, 0x22, 0x00, 0x1A, 0x10, 0xCC, 0xF0, + 0x00, 0x09, 0x84, 0x80, 0x19, 0xE4, 0x04, 0x00, 0x06, 0x12, 0x9E, 0xE7, 0x12, 0x00, 0x08, 0x10, + 0xCB, 0xF0, 0x08, 0x09, 0x9E, 0xE7, 0x24, 0x00, 0xB1, 0xF0, 0x08, 0x09, 0x05, 0xF0, 0x1A, 0x09, + 0x09, 0xF0, 0x20, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0xE4, 0x10, 0x00, 0xF2, 0x5C, 0x0B, 0xE9, 0x10, + 0x9C, 0x32, 0x82, 0xE7, 0x20, 0x00, 0x32, 0x1C, 0xE9, 0x09, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, + 0xFE, 0x09, 0x69, 0x08, 0x01, 0xF0, 0x40, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0x00, 0xF0, 0x34, 0x09, + 0x30, 0x44, 0x06, 0x12, 0x9E, 0xE7, 0x42, 0x00, 0xB8, 0x10, 0x04, 0xF6, 0x01, 0x00, 0xB3, 0x45, + 0x74, 0x12, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x22, 0x13, 0x4B, 0xE4, 0x02, 0x00, 0x36, 0x12, + 0x4B, 0xE4, 0x28, 0x00, 0xAC, 0x13, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0x03, 0xF6, + 0xD0, 0x00, 0xFA, 0x14, 0x82, 0xE7, 0x01, 0x00, 0x00, 0xF0, 0x80, 0x01, 0x9E, 0xE7, 0x44, 0x00, + 0x4B, 0xE4, 0x02, 0x00, 0x06, 0x12, 0x03, 0xE6, 0x02, 0x00, 0x76, 0x10, 0x00, 0xF2, 0x9E, 0x0D, + 0x03, 0xE6, 0x02, 0x00, 0x6C, 0x10, 0x00, 0xF2, 0x9E, 0x0D, 0x19, 0x82, 0x34, 0x46, 0x0A, 0x13, + 0x03, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x43, 0x00, 0x68, 0x10, 0x04, 0x80, 0x30, 0xE4, 0x20, 0x00, + 0x04, 0x40, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0x82, 0xE7, 0x01, 0x00, 0x06, 0xF7, + 0x02, 0x00, 0x00, 0xF0, 0x08, 0x03, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x06, 0x12, 0x03, 0xE6, + 0x02, 0x00, 0x3E, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x3A, 0x12, 0x04, 0x80, 0x18, 0xE4, + 0xFD, 0x00, 0x04, 0x40, 0x1C, 0x1C, 0x9D, 0xF0, 0xE6, 0x09, 0x1C, 0x1C, 0x9D, 0xF0, 0xEC, 0x09, + 0xC1, 0x10, 0x9E, 0xE7, 0x13, 0x00, 0x0A, 0x10, 0x9E, 0xE7, 0x41, 0x00, 0x04, 0x10, 0x9E, 0xE7, + 0x24, 0x00, 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0xD5, 0xF0, 0x8A, 0x02, 0x04, 0xE6, 0x04, 0x00, + 0x06, 0x10, 0x04, 0xE6, 0x04, 0x00, 0x9D, 0x41, 0x1C, 0x42, 0x9F, 0xE7, 0x00, 0x00, 0x06, 0xF7, + 0x02, 0x00, 0x03, 0xF6, 0xE0, 0x00, 0x3C, 0x14, 0x44, 0x58, 0x45, 0x58, 0x00, 0xF2, 0xF2, 0x0D, + 0x00, 0xF2, 0x7A, 0x10, 0x00, 0xF2, 0xC2, 0x0F, 0x3C, 0x14, 0x1E, 0x1C, 0x00, 0xF0, 0x80, 0x01, + 0x12, 0x1C, 0x22, 0x1C, 0xD2, 0x14, 0x00, 0xF0, 0x72, 0x01, 0x83, 0x59, 0x03, 0xDC, 0x73, 0x57, + 0x80, 0x5D, 0x00, 0x16, 0x83, 0x59, 0x03, 0xDC, 0x38, 0x54, 0x70, 0x57, 0x33, 0x54, 0x3B, 0x54, + 0x80, 0x5D, 0x00, 0x16, 0x03, 0x57, 0x83, 0x59, 0x38, 0x54, 0x00, 0xCC, 0x00, 0x16, 0x03, 0x57, + 0x83, 0x59, 0x00, 0x4C, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, 0x01, 0x00, 0x0E, 0x12, 0x48, 0xE4, + 0x05, 0x00, 0x08, 0x12, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0xC1, 0x5A, 0x3A, 0x55, + 0x02, 0xEC, 0xB5, 0x00, 0x45, 0x59, 0x00, 0xF2, 0xF2, 0x0D, 0x83, 0x58, 0x30, 0xE7, 0x00, 0x00, + 0x10, 0x4D, 0x30, 0xE7, 0x40, 0x00, 0x10, 0x4F, 0x38, 0x90, 0xBA, 0x90, 0x10, 0x5C, 0x80, 0x5C, + 0x83, 0x5A, 0x10, 0x4E, 0x04, 0xEA, 0xB5, 0x00, 0x43, 0x5B, 0x03, 0xF4, 0xE0, 0x00, 0x83, 0x59, + 0x04, 0xCC, 0x01, 0x4A, 0x0A, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, 0x00, 0xF2, 0x34, 0x10, + 0x00, 0x16, 0x08, 0x1C, 0x00, 0xFC, 0xAC, 0x00, 0x06, 0x58, 0x67, 0x18, 0x18, 0xF4, 0x8F, 0xE1, + 0x01, 0xFC, 0xAE, 0x00, 0x19, 0xF4, 0x70, 0x1E, 0xB0, 0x54, 0x07, 0x58, 0x00, 0xFC, 0xB0, 0x00, + 0x08, 0x58, 0x00, 0xFC, 0xB2, 0x00, 0x09, 0x58, 0x0A, 0x1C, 0x00, 0xE6, 0x0F, 0x00, 0x00, 0xEA, + 0xB9, 0x00, 0x38, 0x54, 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFA, 0xB6, 0x00, 0x18, 0x1C, 0x14, 0x1C, + 0x10, 0x1C, 0x32, 0x1C, 0x12, 0x1C, 0x00, 0x16, 0x3E, 0x57, 0x0C, 0x14, 0x0E, 0x47, 0x07, 0xE6, + 0x10, 0x00, 0xCE, 0x47, 0xF5, 0x13, 0x00, 0x16, 0x00, 0xF2, 0x9E, 0x0D, 0x02, 0x4B, 0x03, 0xF6, + 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x20, 0x12, 0x44, 0x58, 0x45, 0x58, 0x9E, 0xE7, + 0x15, 0x00, 0x9C, 0xE7, 0x04, 0x00, 0x00, 0xF2, 0xF2, 0x0D, 0x00, 0xF2, 0x7A, 0x10, 0x00, 0xF2, + 0xC2, 0x0F, 0x00, 0xF2, 0x76, 0x0A, 0x1E, 0x1C, 0xD5, 0x10, 0x00, 0x16, 0x69, 0x08, 0x48, 0xE4, + 0x04, 0x00, 0x64, 0x12, 0x48, 0xE4, 0x02, 0x00, 0x20, 0x12, 0x48, 0xE4, 0x03, 0x00, 0x1A, 0x12, + 0x48, 0xE4, 0x08, 0x00, 0x14, 0x12, 0x48, 0xE4, 0x01, 0x00, 0xF0, 0x12, 0x48, 0xE4, 0x07, 0x00, + 0x12, 0x12, 0x01, 0xE6, 0x07, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x05, 0xF0, + 0x5C, 0x0B, 0x00, 0x16, 0x00, 0xE6, 0x01, 0x00, 0x00, 0xEA, 0x99, 0x00, 0x02, 0x80, 0x48, 0xE4, + 0x03, 0x00, 0xB9, 0x12, 0x48, 0xE4, 0x06, 0x00, 0xB3, 0x12, 0x01, 0xE6, 0x06, 0x00, 0x00, 0xF2, + 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, 0x01, 0xF0, + 0x18, 0x0A, 0x00, 0xF0, 0xFE, 0x09, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, 0x10, 0x00, 0x1C, 0x12, + 0x82, 0xE7, 0x08, 0x00, 0x3C, 0x56, 0x03, 0x82, 0x00, 0xF2, 0xDE, 0x0D, 0x30, 0xE7, 0x08, 0x00, + 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF0, 0x80, 0x01, 0x6C, 0x19, 0xED, 0x19, + 0x5D, 0xF0, 0xD0, 0x0B, 0x44, 0x55, 0xE5, 0x55, 0x59, 0xF0, 0x4E, 0x0C, 0x04, 0x55, 0xA5, 0x55, + 0x1F, 0x80, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, 0x49, 0x44, 0x2E, 0x13, 0x01, 0xEC, + 0xB8, 0x00, 0x41, 0xE4, 0x02, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x49, 0xE4, 0x11, 0x00, 0x59, 0xF0, + 0x2A, 0x0C, 0x01, 0xE6, 0x17, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x02, 0x4B, 0x88, 0x90, 0xAC, 0x50, + 0x8A, 0x90, 0xAE, 0x50, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, 0x10, 0x44, 0x02, 0x4B, + 0x1F, 0x40, 0xC0, 0x44, 0x00, 0xF2, 0xB0, 0x0D, 0x04, 0x55, 0xA5, 0x55, 0x9F, 0x10, 0x0C, 0x51, + 0x8E, 0x51, 0x30, 0x90, 0xB2, 0x90, 0x00, 0x56, 0xA1, 0x56, 0x30, 0x50, 0xB2, 0x50, 0x34, 0x90, + 0xB6, 0x90, 0x40, 0x56, 0xE1, 0x56, 0x34, 0x50, 0xB6, 0x50, 0x65, 0x10, 0xB1, 0xF0, 0x6C, 0x0C, + 0x85, 0xF0, 0xC6, 0x0B, 0xE9, 0x09, 0x4B, 0xE4, 0x03, 0x00, 0x78, 0x12, 0x4B, 0xE4, 0x02, 0x00, + 0x01, 0x13, 0xB1, 0xF0, 0x82, 0x0C, 0x85, 0xF0, 0xC6, 0x0B, 0x69, 0x08, 0x48, 0xE4, 0x03, 0x00, + 0xD5, 0xF0, 0x82, 0x0B, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0xC6, 0x0B, 0xE8, 0x09, 0x3C, 0x56, + 0x00, 0xFC, 0x20, 0x01, 0x98, 0x57, 0x02, 0x13, 0xBB, 0x45, 0x4B, 0xE4, 0x00, 0x00, 0x08, 0x12, + 0x03, 0xE6, 0x01, 0x00, 0x04, 0xF6, 0x00, 0x80, 0xA8, 0x14, 0xD2, 0x14, 0x30, 0x1C, 0x02, 0x80, + 0x48, 0xE4, 0x03, 0x00, 0x10, 0x13, 0x00, 0xFC, 0xB6, 0x00, 0x98, 0x57, 0x02, 0x13, 0x4C, 0x1C, + 0x3E, 0x1C, 0x00, 0xF0, 0x8A, 0x0B, 0x00, 0xFC, 0x24, 0x01, 0xB0, 0x57, 0x00, 0xFA, 0x24, 0x01, + 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0x8A, 0x0B, 0x00, 0xF2, 0x88, 0x0E, + 0x00, 0xF0, 0x8A, 0x0B, 0xB1, 0xF0, 0xF4, 0x0C, 0x85, 0xF0, 0x82, 0x0B, 0x69, 0x08, 0x48, 0xE4, + 0x01, 0x00, 0xD5, 0xF0, 0x82, 0x0B, 0xFC, 0x14, 0x42, 0x58, 0x6C, 0x14, 0x80, 0x14, 0x30, 0x1C, + 0x4A, 0xF4, 0x02, 0x00, 0x55, 0xF0, 0x82, 0x0B, 0x4A, 0xF4, 0x01, 0x00, 0x0E, 0x12, 0x02, 0x80, + 0x48, 0xE4, 0x03, 0x00, 0x06, 0x13, 0x3E, 0x1C, 0x00, 0xF0, 0x8A, 0x0B, 0x00, 0xFC, 0xB6, 0x00, + 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, + 0x8A, 0x0B, 0x00, 0xF2, 0xB6, 0x0E, 0x00, 0xF0, 0x8A, 0x0B, 0x4C, 0x1C, 0xB1, 0xF0, 0x4C, 0x0D, + 0x85, 0xF0, 0x58, 0x0D, 0x69, 0x08, 0xF3, 0x10, 0x86, 0xF0, 0x60, 0x0D, 0x4E, 0x1C, 0x89, 0x48, + 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, + 0xFF, 0x7F, 0x30, 0x56, 0x00, 0x5C, 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, + 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x30, 0x56, 0x00, 0x5C, 0x00, 0x16, 0x00, 0xF6, + 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x0B, 0x58, 0x00, 0x16, 0x03, 0xF6, + 0x24, 0x01, 0x00, 0xF2, 0x54, 0x0A, 0x03, 0xF6, 0xB6, 0x00, 0x00, 0xF2, 0x54, 0x0A, 0x00, 0x16, + 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, 0x18, 0xF4, 0xFF, 0x00, 0x00, 0x54, 0x00, 0x54, 0x00, 0x54, + 0x00, 0xF4, 0x08, 0x00, 0xE1, 0x18, 0x80, 0x54, 0x03, 0x58, 0x00, 0xDD, 0x01, 0xDD, 0x02, 0xDD, + 0x03, 0xDC, 0x02, 0x4B, 0x30, 0x50, 0xB2, 0x50, 0x34, 0x51, 0xB6, 0x51, 0x00, 0x16, 0x45, 0x5A, + 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, 0x05, 0xF4, 0x02, 0x12, 0x83, 0x5A, + 0x00, 0x16, 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, 0x05, 0xF4, 0x00, 0x12, + 0x83, 0x5A, 0x00, 0x16, 0x38, 0x54, 0xBB, 0x55, 0x3C, 0x56, 0xBD, 0x56, 0x00, 0xF2, 0x0E, 0x11, + 0x85, 0xF0, 0x7E, 0x0E, 0xE9, 0x09, 0xC1, 0x59, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0x7E, 0x0E, + 0xE8, 0x0A, 0x83, 0x55, 0x83, 0x55, 0x4B, 0xF4, 0x90, 0x01, 0x5C, 0xF0, 0x32, 0x0E, 0xBD, 0x56, + 0x40, 0x10, 0x4B, 0xF4, 0x30, 0x00, 0x59, 0xF0, 0x44, 0x0E, 0x01, 0xF6, 0x0C, 0x00, 0x00, 0xF6, + 0x01, 0x00, 0x2E, 0x10, 0x02, 0xFC, 0x9C, 0x00, 0x9A, 0x57, 0x14, 0x13, 0x4B, 0xF4, 0x64, 0x00, + 0x59, 0xF0, 0x60, 0x0E, 0x03, 0xF6, 0x64, 0x00, 0x01, 0xF6, 0x19, 0x00, 0x00, 0xF6, 0x01, 0x00, + 0x43, 0xF4, 0x33, 0x00, 0x56, 0xF0, 0x72, 0x0E, 0x04, 0xF4, 0x00, 0x01, 0x43, 0xF4, 0x19, 0x00, + 0xF3, 0x10, 0xB4, 0x56, 0xC3, 0x58, 0x02, 0xFC, 0x9E, 0x00, 0x9A, 0x57, 0x08, 0x13, 0x3C, 0x56, + 0x00, 0xF6, 0x02, 0x00, 0x00, 0x16, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, + 0x86, 0xF0, 0xB4, 0x0E, 0x09, 0xE7, 0x02, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xB4, 0x0E, + 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xB4, 0x0E, 0x4E, 0x1C, 0x89, 0x49, + 0x00, 0xF2, 0x0E, 0x11, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, + 0xEE, 0x0E, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xEE, 0x0E, 0x09, 0xE7, + 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xEE, 0x0E, 0x89, 0x49, 0x00, 0xF2, 0x0E, 0x11, + 0x86, 0xF0, 0xEE, 0x0E, 0x4E, 0x1C, 0x89, 0x4A, 0x00, 0xF2, 0x0E, 0x11, 0x00, 0x16, 0x3C, 0x56, + 0x00, 0x16, 0x00, 0xEC, 0x26, 0x01, 0x48, 0xE4, 0x01, 0x00, 0x1E, 0x13, 0x38, 0x44, 0x00, 0xEA, + 0x26, 0x01, 0x49, 0xF4, 0x00, 0x00, 0x04, 0x12, 0x4E, 0x1C, 0x02, 0x10, 0x4C, 0x1C, 0x01, 0xEC, + 0x27, 0x01, 0x89, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x02, 0x14, 0x00, 0x16, 0x85, 0xF0, 0x4E, 0x0F, + 0x38, 0x54, 0x00, 0xEA, 0x99, 0x00, 0x00, 0xF2, 0x5C, 0x0B, 0x02, 0x80, 0x48, 0xE4, 0x06, 0x00, + 0x1C, 0x13, 0x00, 0xEC, 0x99, 0x00, 0x48, 0xE4, 0x01, 0x00, 0x0A, 0x12, 0x04, 0x80, 0x30, 0xE4, + 0x01, 0x00, 0x04, 0x40, 0x08, 0x10, 0x04, 0x80, 0x18, 0xE4, 0xFE, 0x00, 0x04, 0x40, 0x00, 0x16, + 0x02, 0xF6, 0xE0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x81, 0x48, 0x22, 0x12, 0x00, 0x4E, + 0x83, 0x5A, 0x90, 0x4C, 0x20, 0xE7, 0x00, 0x00, 0xC3, 0x58, 0x1B, 0xF4, 0xFF, 0x00, 0x83, 0x55, + 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, 0x8B, 0x55, 0x83, 0x59, 0x00, 0x4E, 0x00, 0x16, + 0x00, 0x4E, 0x02, 0xF6, 0xF0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x00, 0x4E, 0x83, 0x5A, 0x30, 0xE7, + 0x00, 0x00, 0x20, 0xE7, 0x00, 0x00, 0x00, 0x16, 0x02, 0xF6, 0xF0, 0x00, 0x02, 0x57, 0x03, 0x59, + 0x01, 0xCC, 0x00, 0x4E, 0x83, 0x5A, 0x30, 0xE7, 0x00, 0x00, 0x80, 0x4C, 0xC3, 0x58, 0x1B, 0xF4, + 0xFF, 0x00, 0x83, 0x55, 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, 0x83, 0x59, 0x00, 0x4E, + 0x00, 0x16, 0x03, 0xF6, 0xE0, 0x00, 0x03, 0x57, 0x83, 0x59, 0x3A, 0x55, 0x02, 0xCC, 0x45, 0x5A, + 0x00, 0xF2, 0xF2, 0x0D, 0xC0, 0x5A, 0x40, 0x5C, 0x38, 0x54, 0x00, 0xCD, 0x01, 0xCC, 0x4A, 0x46, + 0x0A, 0x13, 0x83, 0x59, 0x00, 0x4C, 0x01, 0x48, 0x16, 0x13, 0x0C, 0x10, 0xC5, 0x58, 0x00, 0xF2, + 0xF2, 0x0D, 0x00, 0x4C, 0x01, 0x48, 0x08, 0x13, 0x05, 0xF6, 0xF0, 0x00, 0x05, 0x57, 0x08, 0x10, + 0x45, 0x58, 0x00, 0xF2, 0xF2, 0x0D, 0x8D, 0x56, 0x83, 0x5A, 0x80, 0x4C, 0x05, 0x17, 0x00, 0x16, + 0x02, 0x4B, 0x06, 0xF7, 0x04, 0x00, 0x62, 0x0B, 0x03, 0x82, 0x00, 0xF2, 0xDE, 0x0D, 0x02, 0x80, + 0x00, 0x4C, 0x45, 0xF4, 0x02, 0x00, 0x52, 0x14, 0x06, 0xF7, 0x02, 0x00, 0x06, 0x14, 0x00, 0xF2, + 0x50, 0x0F, 0x00, 0x16, 0x02, 0x4B, 0x01, 0xF6, 0xFF, 0x00, 0x38, 0x1C, 0x05, 0xF4, 0x04, 0x00, + 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x1D, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, 0x4A, 0x10, 0x9C, 0x14, + 0x01, 0x48, 0x1C, 0x13, 0x0E, 0xF7, 0x3C, 0x00, 0x03, 0xF7, 0x04, 0x00, 0xAF, 0x19, 0x03, 0x42, + 0x45, 0xF4, 0x02, 0x00, 0x83, 0x5A, 0x02, 0xCC, 0x02, 0x41, 0x45, 0xF4, 0x02, 0x00, 0x00, 0x16, + 0x91, 0x44, 0xD5, 0xF0, 0x3A, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x01, 0xF6, 0xFF, 0x00, 0x38, 0x1C, + 0x05, 0xF4, 0x04, 0x00, 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x0E, 0xF7, 0x3C, 0x00, 0x03, 0xF7, + 0x04, 0x00, 0x0F, 0x79, 0x1C, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, 0x98, 0x10, 0x4E, 0x14, 0x01, 0x48, + 0x06, 0x13, 0x45, 0xF4, 0x04, 0x00, 0x00, 0x16, 0x91, 0x44, 0xD5, 0xF0, 0x7E, 0x10, 0x00, 0xF0, + 0x9E, 0x02, 0x02, 0xF6, 0xFF, 0x00, 0x38, 0x1C, 0x2C, 0xBC, 0xAE, 0xBC, 0xE2, 0x08, 0x00, 0xEC, + 0xB8, 0x00, 0x02, 0x48, 0x1D, 0xF7, 0x80, 0x00, 0xB8, 0xF0, 0xC8, 0x10, 0x1E, 0x14, 0x01, 0x48, + 0x0E, 0x13, 0x0E, 0xF7, 0x80, 0x00, 0x38, 0x54, 0x03, 0x58, 0xAF, 0x19, 0x82, 0x48, 0x00, 0x16, + 0x82, 0x48, 0x12, 0x45, 0xD5, 0xF0, 0xB6, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x39, 0xF0, 0xF4, 0x10, + 0x38, 0x44, 0x00, 0x16, 0x7E, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x04, 0x13, 0x61, 0x18, 0x00, 0x16, + 0x38, 0x1C, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xF1, 0x12, 0xE3, 0x10, 0x30, 0x44, + 0x30, 0x44, 0x30, 0x44, 0xB1, 0xF0, 0x14, 0x11, 0x00, 0x16, 0x3E, 0x57, 0x03, 0xF6, 0xE0, 0x00, + 0x03, 0x57, 0x83, 0x59, 0x04, 0xCC, 0x01, 0x4A, 0x6A, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, + 0x02, 0x4B, 0x70, 0x14, 0x34, 0x13, 0x02, 0x80, 0x48, 0xE4, 0x08, 0x00, 0x18, 0x12, 0x9C, 0xE7, + 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, 0x00, 0xF2, 0xC2, 0x0F, 0x00, 0xF2, 0x76, 0x0A, 0x1E, 0x1C, + 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x30, 0xE4, 0x10, 0x00, 0x04, 0x40, 0x00, 0xF2, 0xDE, 0x0D, + 0x20, 0xE7, 0x01, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x04, 0xDC, 0x01, 0x4A, 0x24, 0x12, + 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, 0x43, 0x5B, 0x06, 0xEC, 0x98, 0x00, 0x00, 0xF2, 0x34, 0x10, + 0xC6, 0x59, 0x20, 0x14, 0x0A, 0x13, 0x00, 0xF2, 0xC2, 0x0F, 0x00, 0xF2, 0x10, 0x10, 0xA7, 0x10, + 0x83, 0x5A, 0xD7, 0x10, 0x0E, 0x47, 0x07, 0xE6, 0x10, 0x00, 0xCE, 0x47, 0x5A, 0xF0, 0x1C, 0x11, + 0xB9, 0x54, 0x00, 0x16, 0x14, 0x90, 0x96, 0x90, 0x02, 0xFC, 0xA8, 0x00, 0x03, 0xFC, 0xAA, 0x00, + 0x48, 0x55, 0x02, 0x13, 0xC9, 0x55, 0x00, 0x16, 0x00, 0xEC, 0xBA, 0x00, 0x10, 0x44, 0x00, 0xEA, + 0xBA, 0x00, 0x00, 0x16, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x10, 0x44, 0x00, 0x4C, + 0x00, 0x16 }; + +unsigned short _adv_mcode_size ASC_INITDATA = + sizeof(_adv_mcode_buf); /* 0x11D2 */ +unsigned long _adv_mcode_chksum ASC_INITDATA = 0x0347D07AUL; + +/* a_init.c */ +/* + * EEPROM Configuration. + * + * All drivers should use this structure to set the default EEPROM + * configuration. The BIOS now uses this structure when it is built. + * Additional structure information can be found in a_condor.h where + * the structure is defined. + */ +STATIC ADVEEP_CONFIG +Default_EEPROM_Config ASC_INITDATA = { + ADV_EEPROM_BIOS_ENABLE, /* cfg_msw */ + 0x0000, /* cfg_lsw */ + 0xFFFF, /* disc_enable */ + 0xFFFF, /* wdtr_able */ + 0xFFFF, /* sdtr_able */ + 0xFFFF, /* start_motor */ + 0xFFFF, /* tagqng_able */ + 0xFFFF, /* bios_scan */ + 0, /* scam_tolerant */ + 7, /* adapter_scsi_id */ + 0, /* bios_boot_delay */ + 3, /* scsi_reset_delay */ + 0, /* bios_id_lun */ + 0, /* termination */ + 0, /* reserved1 */ + 0xFFEF, /* bios_ctrl */ + 0xFFFF, /* ultra_able */ + 0, /* reserved2 */ + ASC_DEF_MAX_HOST_QNG, /* max_host_qng */ + ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */ + 0, /* dvc_cntl */ + 0, /* bug_fix */ + 0, /* serial_number_word1 */ + 0, /* serial_number_word2 */ + 0, /* serial_number_word3 */ + 0, /* check_sum */ + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* oem_name[16] */ + 0, /* dvc_err_code */ + 0, /* adv_err_code */ + 0, /* adv_err_addr */ + 0, /* saved_dvc_err_code */ + 0, /* saved_adv_err_code */ + 0, /* saved_adv_err_addr */ + 0 /* num_of_err */ +}; + +/* + * Initialize the ADV_DVC_VAR structure. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + */ +ASC_INITFUNC( +int +AdvInitGetConfig(ADV_DVC_VAR *asc_dvc) +) +{ + ushort warn_code; + AdvPortAddr iop_base; + uchar pci_cmd_reg; + int status; + + warn_code = 0; + asc_dvc->err_code = 0; + iop_base = asc_dvc->iop_base; + + /* + * PCI Command Register + */ + + if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc, + AscPCIConfigCommandRegister)) + & AscPCICmdRegBits_BusMastering) + != AscPCICmdRegBits_BusMastering) + { + pci_cmd_reg |= AscPCICmdRegBits_BusMastering; + + DvcAdvWritePCIConfigByte(asc_dvc, + AscPCIConfigCommandRegister, pci_cmd_reg); + + if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)) + & AscPCICmdRegBits_BusMastering) + != AscPCICmdRegBits_BusMastering) + { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } + } + + /* + * PCI Latency Timer + * + * If the "latency timer" register is 0x20 or above, then we don't need + * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it + * comes up less than 0x20). + */ + if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) { + DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer, 0x20); + if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) + { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } + } + + /* + * Save the state of the PCI Configuration Command Register + * "Parity Error Response Control" Bit. If the bit is clear (0), + * in AdvInitAsc3550Driver() tell the microcode to ignore DMA + * parity errors. + */ + asc_dvc->cfg->control_flag = 0; + if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister) + & AscPCICmdRegBits_ParErrRespCtrl)) == 0) + { + asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR; + } + + asc_dvc->cur_host_qng = 0; + + asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) | + ADV_LIB_VERSION_MINOR; + asc_dvc->cfg->chip_version = + AdvGetChipVersion(iop_base, asc_dvc->bus_type); + + /* + * Reset the chip to start and allow register writes. + */ + if (AdvFindSignature(iop_base) == 0) + { + asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; + return ADV_ERROR; + } + else { + + AdvResetChip(asc_dvc); + + if ((status = AdvInitFromEEP(asc_dvc)) == ADV_ERROR) + { + return ADV_ERROR; + } + warn_code |= status; + + /* + * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus + * Resets should be performed. + */ + if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) + { + AdvResetSCSIBus(asc_dvc); + } + } + + return warn_code; +} + +/* + * Initialize the ASC3550. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + */ +ASC_INITFUNC( +int +AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) +) +{ + AdvPortAddr iop_base; + ushort warn_code; + ulong sum; + int begin_addr; + int end_addr; + int code_sum; + int word; + int rql_addr; /* RISC Queue List address */ + int i; + ushort scsi_cfg1; + uchar biosmem[ASC_MC_BIOSLEN]; /* BIOS RISC Memory 0x40-0x8F. */ + + /* If there is already an error, don't continue. */ + if (asc_dvc->err_code != 0) + { + return ADV_ERROR; + } + + warn_code = 0; + iop_base = asc_dvc->iop_base; + + /* + * Save the RISC memory BIOS region before writing the microcode. + * The BIOS may already be loaded and using its RISC LRAM region + * so its region must be saved and restored. + * + * Note: This code makes the assumption, which is currently true, + * that a chip reset does not clear RISC LRAM. + */ + for (i = 0; i < ASC_MC_BIOSLEN; i++) + { + AdvReadByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]); + } + + /* + * Load the Microcode + * + * Write the microcode image to RISC memory starting at address 0. + */ + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + for (word = 0; word < _adv_mcode_size; word += 2) + { + AdvWriteWordAutoIncLram(iop_base, + *((ushort *) (&_adv_mcode_buf[word]))); + } + + /* + * Clear the rest of Condor's Internal RAM (8KB). + */ + for (; word < ADV_CONDOR_MEMSIZE; word += 2) + { + AdvWriteWordAutoIncLram(iop_base, 0); + } + + /* + * Verify the microcode checksum. + */ + sum = 0; + AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); + for (word = 0; word < _adv_mcode_size; word += 2) + { + sum += AdvReadWordAutoIncLram(iop_base); + } + + if (sum != _adv_mcode_chksum) + { + asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; + return ADV_ERROR; + } + + /* + * Restore the RISC memory BIOS region. + */ + for (i = 0; i < ASC_MC_BIOSLEN; i++) + { + AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]); + } + + /* + * Calculate and write the microcode code checksum to the microcode + * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); + AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); + code_sum = 0; + for (word = begin_addr; word < end_addr; word += 2) + { + code_sum += *((ushort *) (&_adv_mcode_buf[word])); + } + AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); + + /* + * Read microcode version and date. + */ + AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date); + AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version); + + /* + * Initialize microcode operating variables + */ + AdvWriteWordLram(iop_base, ASC_MC_ADAPTER_SCSI_ID, + asc_dvc->chip_scsi_id); + + /* + * If the PCI Configuration Command Register "Parity Error Response + * Control" Bit was clear (0), then set the microcode variable + * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode + * to ignore DMA parity errors. + */ + if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) + { + /* + * Note: Don't remove the use of a temporary variable in + * the following code, otherwise the Microsoft C compiler + * will turn the following lines into a no-op. + */ + AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + word |= CONTROL_FLAG_IGNORE_PERR; + AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); + } + + /* + * Set default microcode operating variables for WDTR, SDTR, and + * command tag queuing based on the EEPROM configuration values. + * + * These ADV_DVC_VAR fields and the microcode variables will be + * changed in AdvInquiryHandling() if it is found a device is + * incapable of a particular feature. + */ + + /* + * Set the microcode ULTRA target mask from EEPROM value. The + * SDTR target mask overrides the ULTRA target mask in the + * microcode so it is safe to set this value without determining + * whether the device supports SDTR. + * + * Note: There is no way to know whether a device supports ULTRA + * speed without attempting a SDTR ULTRA speed negotiation with + * the device. The device will reject the speed if it does not + * support it by responding with an SDTR message containing a + * slower speed. + */ + AdvWriteWordLram(iop_base, ASC_MC_ULTRA_ABLE, asc_dvc->ultra_able); + AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable); + + + /* + * Set SCSI_CFG0 Microcode Default Value. + * + * The microcode will set the SCSI_CFG0 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, + PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id); + + /* + * Determine SCSI_CFG1 Microcode Default Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + + /* Read current SCSI_CFG1 Register value. */ + scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + + /* + * If all three connectors are in use, return an error. + */ + if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || + (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) + { + asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; + return ADV_ERROR; + } + + /* + * If the internal narrow cable is reversed all of the SCSI_CTRL + * register signals will be set. Check for and return an error if + * this condition is found. + */ + if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) + { + asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; + return ADV_ERROR; + } + + /* + * If this is a differential board and a single-ended device + * is attached to one of the connectors, return an error. + */ + if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) + { + asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; + return ADV_ERROR; + } + + /* + * If automatic termination control is enabled, then set the + * termination value based on a table listed in a_condor.h. + * + * If manual termination was specified with an EEPROM setting + * then 'termination' was set-up in AdvInitFromEEP() and + * is ready to be 'ored' into SCSI_CFG1. + */ + if (asc_dvc->cfg->termination == 0) + { + /* + * The software always controls termination by setting TERM_CTL_SEL. + * If TERM_CTL_SEL were set to 0, the hardware would set termination. + */ + asc_dvc->cfg->termination |= TERM_CTL_SEL; + + switch(scsi_cfg1 & CABLE_DETECT) + { + /* TERM_CTL_H: on, TERM_CTL_L: on */ + case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF: + asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); + break; + + /* TERM_CTL_H: on, TERM_CTL_L: off */ + case 0x1: case 0x5: case 0x9: case 0xA: case 0xC: + asc_dvc->cfg->termination |= TERM_CTL_H; + break; + + /* TERM_CTL_H: off, TERM_CTL_L: off */ + case 0x2: case 0x6: + break; + } + } + + /* + * Clear any set TERM_CTL_H and TERM_CTL_L bits. + */ + scsi_cfg1 &= ~TERM_CTL; + + /* + * Invert the TERM_CTL_H and TERM_CTL_L bits and then + * set 'scsi_cfg1'. The TERM_POL bit does not need to be + * referenced, because the hardware internally inverts + * the Termination High and Low bits if TERM_POL is set. + */ + scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL)); + + /* + * Set SCSI_CFG1 Microcode Default Value + * + * Set filter value and possibly modified termination control + * bits in the Microcode SCSI_CFG1 Register Value. + * + * The microcode will set the SCSI_CFG1 register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, + FLTR_11_TO_20NS | scsi_cfg1); + + /* + * Set SEL_MASK Microcode Default Value + * + * The microcode will set the SEL_MASK register using this value + * after it is started below. + */ + AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, + ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); + + /* + * Link all the RISC Queue Lists together in a doubly-linked + * NULL terminated list. + * + * Skip the NULL (0) queue which is not used. + */ + for (i = 1, rql_addr = ASC_MC_RISC_Q_LIST_BASE + ASC_MC_RISC_Q_LIST_SIZE; + i < ASC_MC_RISC_Q_TOTAL_CNT; + i++, rql_addr += ASC_MC_RISC_Q_LIST_SIZE) + { + /* + * Set the current RISC Queue List's RQL_FWD and RQL_BWD pointers + * in a one word write and set the state (RQL_STATE) to free. + */ + AdvWriteWordLram(iop_base, rql_addr, ((i + 1) + ((i - 1) << 8))); + AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE); + } + + /* + * Set the Host and RISC Queue List pointers. + * + * Both sets of pointers are initialized with the same values: + * ASC_MC_RISC_Q_FIRST(0x01) and ASC_MC_RISC_Q_LAST (0xFF). + */ + AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, ASC_MC_RISC_Q_FIRST); + AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, ASC_MC_RISC_Q_LAST); + + AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_READY, ASC_MC_RISC_Q_FIRST); + AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_DONE, ASC_MC_RISC_Q_LAST); + + /* + * Finally, set up the last RISC Queue List (255) with + * a NULL forward pointer. + */ + AdvWriteWordLram(iop_base, rql_addr, (ASC_MC_NULL_Q + ((i - 1) << 8))); + AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE); + + AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, + (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR)); + + /* + * Note: Don't remove the use of a temporary variable in + * the following code, otherwise the Microsoft C compiler + * will turn the following lines into a no-op. + */ + AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); + AdvWriteWordRegister(iop_base, IOPW_PC, word); + + /* finally, finally, gentlemen, start your engine */ + AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); + + return warn_code; +} + +/* + * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and + * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while + * all of this is done. + * + * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. + * + * For a non-fatal error return a warning code. If there are no warnings + * then 0 is returned. + * + * Note: Chip is stopped on entry. + */ +ASC_INITFUNC( +STATIC int +AdvInitFromEEP(ADV_DVC_VAR *asc_dvc) +) +{ + AdvPortAddr iop_base; + ushort warn_code; + ADVEEP_CONFIG eep_config; + int i; + + iop_base = asc_dvc->iop_base; + + warn_code = 0; + + /* + * Read the board's EEPROM configuration. + * + * Set default values if a bad checksum is found. + */ + if (AdvGetEEPConfig(iop_base, &eep_config) != eep_config.check_sum) + { + warn_code |= ASC_WARN_EEPROM_CHKSUM; + + /* + * Set EEPROM default values. + */ + for (i = 0; i < sizeof(ADVEEP_CONFIG); i++) + { + *((uchar *) &eep_config + i) = + *((uchar *) &Default_EEPROM_Config + i); + } + + /* + * Assume the 6 byte board serial number that was read + * from EEPROM is correct even if the EEPROM checksum + * failed. + */ + eep_config.serial_number_word3 = + AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1); + eep_config.serial_number_word2 = + AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2); + eep_config.serial_number_word1 = + AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3); + AdvSetEEPConfig(iop_base, &eep_config); + } + + /* + * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the + * EEPROM configuration that was read. + * + * This is the mapping of EEPROM fields to Adv Library fields. + */ + asc_dvc->wdtr_able = eep_config.wdtr_able; + asc_dvc->sdtr_able = eep_config.sdtr_able; + asc_dvc->ultra_able = eep_config.ultra_able; + asc_dvc->tagqng_able = eep_config.tagqng_able; + asc_dvc->cfg->disc_enable = eep_config.disc_enable; + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); + asc_dvc->start_motor = eep_config.start_motor; + asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; + asc_dvc->cfg->bios_boot_wait = eep_config.bios_boot_delay; + asc_dvc->bios_ctrl = eep_config.bios_ctrl; + asc_dvc->no_scam = eep_config.scam_tolerant; + asc_dvc->cfg->serial1 = eep_config.serial_number_word1; + asc_dvc->cfg->serial2 = eep_config.serial_number_word2; + asc_dvc->cfg->serial3 = eep_config.serial_number_word3; + + /* + * Set the host maximum queuing (max. 253, min. 16) and the per device + * maximum queuing (max. 63, min. 4). + */ + if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_host_qng == 0) + { + eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; + } else + { + eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG; + } + } + + if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) + { + /* If the value is zero, assume it is uninitialized. */ + if (eep_config.max_dvc_qng == 0) + { + eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; + } else + { + eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG; + } + } + + /* + * If 'max_dvc_qng' is greater than 'max_host_qng', then + * set 'max_dvc_qng' to 'max_host_qng'. + */ + if (eep_config.max_dvc_qng > eep_config.max_host_qng) + { + eep_config.max_dvc_qng = eep_config.max_host_qng; + } + + /* + * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_CFG 'max_dvc_qng' + * values based on possibly adjusted EEPROM values. + */ + asc_dvc->max_host_qng = eep_config.max_host_qng; + asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; + + + /* + * If the EEPROM 'termination' field is set to automatic (0), then set + * the ADV_DVC_CFG 'termination' field to automatic also. + * + * If the termination is specified with a non-zero 'termination' + * value check that a legal value is set and set the ADV_DVC_CFG + * 'termination' field appropriately. + */ + if (eep_config.termination == 0) + { + asc_dvc->cfg->termination = 0; /* auto termination */ + } else + { + /* Enable manual control with low off / high off. */ + if (eep_config.termination == 1) + { + asc_dvc->cfg->termination = TERM_CTL_SEL; + + /* Enable manual control with low off / high on. */ + } else if (eep_config.termination == 2) + { + asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H; + + /* Enable manual control with low on / high on. */ + } else if (eep_config.termination == 3) + { + asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L; + } else + { + /* + * The EEPROM 'termination' field contains a bad value. Use + * automatic termination instead. + */ + asc_dvc->cfg->termination = 0; + warn_code |= ASC_WARN_EEPROM_TERMINATION; + } + } + + return warn_code; +} + +/* + * Read EEPROM configuration into the specified buffer. + * + * Return a checksum based on the EEPROM configuration read. + */ +ASC_INITFUNC( +STATIC ushort +AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf) +) +{ + ushort wval, chksum; + ushort *wbuf; + int eep_addr; + + wbuf = (ushort *) cfg_buf; + chksum = 0; + + for (eep_addr = ASC_EEP_DVC_CFG_BEGIN; + eep_addr < ASC_EEP_DVC_CFG_END; + eep_addr++, wbuf++) + { + wval = AdvReadEEPWord(iop_base, eep_addr); + chksum += wval; + *wbuf = wval; + } + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + wbuf++; + for (eep_addr = ASC_EEP_DVC_CTL_BEGIN; + eep_addr < ASC_EEP_MAX_WORD_ADDR; + eep_addr++, wbuf++) + { + *wbuf = AdvReadEEPWord(iop_base, eep_addr); + } + return chksum; +} + +/* + * Read the EEPROM from specified location + */ +ASC_INITFUNC( +STATIC ushort +AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) +) +{ + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, + ASC_EEP_CMD_READ | eep_word_addr); + AdvWaitEEPCmd(iop_base); + return AdvReadWordRegister(iop_base, IOPW_EE_DATA); +} + +/* + * Wait for EEPROM command to complete + */ +ASC_INITFUNC( +STATIC void +AdvWaitEEPCmd(AdvPortAddr iop_base) +) +{ + int eep_delay_ms; + + for (eep_delay_ms = 0; eep_delay_ms < ASC_EEP_DELAY_MS; eep_delay_ms++) + { + if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) + { + break; + } + DvcSleepMilliSecond(1); + } + if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == 0) + { + ADV_ASSERT(0); + } + return; +} + +/* + * Write the EEPROM from 'cfg_buf'. + */ +ASC_INITFUNC( +STATIC void +AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf) +) +{ + ushort *wbuf; + ushort addr, chksum; + + wbuf = (ushort *) cfg_buf; + chksum = 0; + + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); + AdvWaitEEPCmd(iop_base); + + /* + * Write EEPROM from word 0 to word 15 + */ + for (addr = ASC_EEP_DVC_CFG_BEGIN; + addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++) + { + chksum += *wbuf; + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + DvcSleepMilliSecond(ASC_EEP_DELAY_MS); + } + + /* + * Write EEPROM checksum at word 18 + */ + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + wbuf++; /* skip over check_sum */ + + /* + * Write EEPROM OEM name at words 19 to 26 + */ + for (addr = ASC_EEP_DVC_CTL_BEGIN; + addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++) + { + AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf); + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); + AdvWaitEEPCmd(iop_base); + } + AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); + AdvWaitEEPCmd(iop_base); + return; +} + +/* + * This function resets the chip and SCSI bus + * + * It is up to the caller to add a delay to let the bus settle after + * calling this function. + * + * The SCSI_CFG0, SCSI_CFG1, and MEM_CFG registers are set-up in + * AdvInitAsc3550Driver(). Here when doing a write to one of these + * registers read first and then write. + * + * Note: A SCSI Bus Reset can not be done until after the EEPROM + * configuration is read to determine whether SCSI Bus Resets + * should be performed. + */ +ASC_INITFUNC( +STATIC void +AdvResetChip(ADV_DVC_VAR *asc_dvc) +) +{ + AdvPortAddr iop_base; + ushort word; + uchar byte; + + iop_base = asc_dvc->iop_base; + + /* + * Reset Chip. + */ + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET); + DvcSleepMilliSecond(100); + AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG); + + /* + * Initialize Chip registers. + * + * Note: Don't remove the use of a temporary variable in the following + * code, otherwise the Microsoft C compiler will turn the following lines + * into a no-op. + */ + byte = AdvReadByteRegister(iop_base, IOPB_MEM_CFG); + byte |= RAM_SZ_8KB; + AdvWriteByteRegister(iop_base, IOPB_MEM_CFG, byte); + + word = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); + word &= ~BIG_ENDIAN; + AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, word); + + /* + * Setting the START_CTL_EMFU 3:2 bits sets a FIFO threshold + * of 128 bytes. This register is only accessible to the host. + */ + AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, + START_CTL_EMFU | READ_CMD_MRM); +} + +/* a_advlib.c */ +/* + * Description: + * Send a SCSI request to the ASC3550 chip + * + * If there is no SG list for the request, set 'sg_entry_cnt' to 0. + * + * If 'sg_real_addr' is non-zero on entry, AscGetSGList() will not be + * called. It is assumed the caller has already initialized 'sg_real_addr'. + * + * Return: + * ADV_SUCCESS(1) - the request is in the mailbox + * ADV_BUSY(0) - total request count > 253, try later + * ADV_ERROR(-1) - invalid scsi request Q + */ +STATIC int +AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, + ADV_SCSI_REQ_Q *scsiq) +{ + if (scsiq == (ADV_SCSI_REQ_Q *) 0L) + { + /* 'scsiq' should never be NULL. */ + ADV_ASSERT(0); + return ADV_ERROR; + } + + return AdvSendScsiCmd(asc_dvc, scsiq); +} + +/* + * Reset SCSI Bus and purge all outstanding requests. + * + * Return Value: + * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset. + * + * Note: Should always return ADV_TRUE. + */ +STATIC int +AdvResetSB(ADV_DVC_VAR *asc_dvc) +{ + int status; + + status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET, 0L, 0); + + AdvResetSCSIBus(asc_dvc); + + return status; +} + +/* + * Reset SCSI Bus and delay. + */ +STATIC void +AdvResetSCSIBus(ADV_DVC_VAR *asc_dvc) +{ + AdvPortAddr iop_base; + ushort scsi_ctrl; + + iop_base = asc_dvc->iop_base; + + /* + * The microcode currently sets the SCSI Bus Reset signal while + * handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET command above. + * But the SCSI Bus Reset Hold Time in the microcode is not deterministic + * (it may in fact be for less than the SCSI Spec. minimum of 25 us). + * Therefore on return the Adv Library sets the SCSI Bus Reset signal + * for ASC_SCSI_RESET_HOLD_TIME_US, which is defined to be greater + * than 25 us. + */ + scsi_ctrl = AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL); + AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL, + scsi_ctrl | ADV_SCSI_CTRL_RSTOUT); + DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US); + AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL, + scsi_ctrl & ~ADV_SCSI_CTRL_RSTOUT); + + DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000); +} + + +/* + * Adv Library Interrupt Service Routine + * + * This function is called by a driver's interrupt service routine. + * The function disables and re-enables interrupts. + * + * When a microcode idle command is completed, the ADV_DVC_VAR + * 'idle_cmd_done' field is set to ADV_TRUE. + * + * Note: AdvISR() can be called when interrupts are disabled or even + * when there is no hardware interrupt condition present. It will + * always check for completed idle commands and microcode requests. + * This is an important feature that shouldn't be changed because it + * allows commands to be completed from polling mode loops. + * + * Return: + * ADV_TRUE(1) - interrupt was pending + * ADV_FALSE(0) - no interrupt was pending + */ +STATIC int +AdvISR(ADV_DVC_VAR *asc_dvc) +{ + AdvPortAddr iop_base; + uchar int_stat; + ushort next_done_loc, target_bit; + int completed_q; + int flags; + ADV_SCSI_REQ_Q *scsiq; + ASC_REQ_SENSE *sense_data; + int ret; + + flags = DvcEnterCritical(); + iop_base = asc_dvc->iop_base; + + if (AdvIsIntPending(iop_base)) + { + ret = ADV_TRUE; + } else + { + ret = ADV_FALSE; + } + + /* Reading the register clears the interrupt. */ + int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG); + + if (int_stat & ADV_INTR_STATUS_INTRB) + { + asc_dvc->idle_cmd_done = ADV_TRUE; + } + + /* + * Notify the driver of a hardware detected SCSI Bus Reset. + */ + if (int_stat & ADV_INTR_STATUS_INTRC) + { + if (asc_dvc->sbreset_callback != 0) + { + (*(ADV_SBRESET_CALLBACK) asc_dvc->sbreset_callback)(asc_dvc); + } + } + + /* + * ASC_MC_HOST_NEXT_DONE (0x129) is actually the last completed RISC + * Queue List request. Its forward pointer (RQL_FWD) points to the + * current completed RISC Queue List request. + */ + AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, next_done_loc); + next_done_loc = ASC_MC_RISC_Q_LIST_BASE + + (next_done_loc * ASC_MC_RISC_Q_LIST_SIZE) + RQL_FWD; + + AdvReadByteLram(iop_base, next_done_loc, completed_q); + + /* Loop until all completed Q's are processed. */ + while (completed_q != ASC_MC_NULL_Q) + { + AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, completed_q); + + next_done_loc = ASC_MC_RISC_Q_LIST_BASE + + (completed_q * ASC_MC_RISC_Q_LIST_SIZE); + + /* + * Read the ADV_SCSI_REQ_Q virtual address pointer from + * the RISC list entry. The microcode has changed the + * ADV_SCSI_REQ_Q physical address to its virtual address. + * + * Refer to comments at the end of AdvSendScsiCmd() for + * more information on the RISC list structure. + */ + { + ushort lsw, msw; + AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR, lsw); + AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR + 2, msw); + + scsiq = (ADV_SCSI_REQ_Q *) (((ulong) msw << 16) | lsw); + } + ADV_ASSERT(scsiq != NULL); + + target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id); + + /* + * Clear request microcode control flag. + */ + scsiq->cntl = 0; + + /* + * Check Condition handling + */ + if ((scsiq->done_status == QD_WITH_ERROR) && + (scsiq->scsi_status == SS_CHK_CONDITION) && + (sense_data = (ASC_REQ_SENSE *) scsiq->vsense_addr) != 0 && + (scsiq->orig_sense_len - scsiq->sense_len) >= ASC_MIN_SENSE_LEN) + { + /* + * Command returned with a check condition and valid + * sense data. + */ + } + /* + * If the command that completed was a SCSI INQUIRY and + * LUN 0 was sent the command, then process the INQUIRY + * command information for the device. + */ + else if (scsiq->done_status == QD_NO_ERROR && + scsiq->cdb[0] == SCSICMD_Inquiry && + scsiq->target_lun == 0) + { + AdvInquiryHandling(asc_dvc, scsiq); + } + + + /* Change the RISC Queue List state to free. */ + AdvWriteByteLram(iop_base, next_done_loc + RQL_STATE, ASC_MC_QS_FREE); + + /* Get the RISC Queue List forward pointer. */ + AdvReadByteLram(iop_base, next_done_loc + RQL_FWD, completed_q); + + /* + * Notify the driver of the completed request by passing + * the ADV_SCSI_REQ_Q pointer to its callback function. + */ + ADV_ASSERT(asc_dvc->cur_host_qng > 0); + asc_dvc->cur_host_qng--; + scsiq->a_flag |= ADV_SCSIQ_DONE; + (*(ADV_ISR_CALLBACK) asc_dvc->isr_callback)(asc_dvc, scsiq); + /* + * Note: After the driver callback function is called, 'scsiq' + * can no longer be referenced. + * + * Fall through and continue processing other completed + * requests... + */ + + /* + * Disable interrupts again in case the driver inadvertently + * enabled interrupts in its callback function. + * + * The DvcEnterCritical() return value is ignored, because + * the 'flags' saved when AdvISR() was first entered will be + * used to restore the interrupt flag on exit. + */ + (void) DvcEnterCritical(); + } + DvcLeaveCritical(flags); + return ret; +} + +/* + * Send an idle command to the chip and wait for completion. + * + * Interrupts do not have to be enabled on entry. + * + * Return Values: + * ADV_TRUE - command completed successfully + * ADV_FALSE - command failed + */ +STATIC int +AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc, + ushort idle_cmd, + ulong idle_cmd_parameter, + int flags) +{ + int last_int_level; + ulong i; + AdvPortAddr iop_base; + int ret; + + asc_dvc->idle_cmd_done = 0; + + last_int_level = DvcEnterCritical(); + iop_base = asc_dvc->iop_base; + + /* + * Write the idle command value after the idle command parameter + * has been written to avoid a race condition. If the order is not + * followed, the microcode may process the idle command before the + * parameters have been written to LRAM. + */ + AdvWriteDWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, idle_cmd_parameter); + AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd); + DvcLeaveCritical(last_int_level); + + /* + * If the 'flags' argument contains the ADV_NOWAIT flag, then + * return with success. + */ + if (flags & ADV_NOWAIT) + { + return ADV_TRUE; + } + + for (i = 0; i < SCSI_WAIT_10_SEC * SCSI_MS_PER_SEC; i++) + { + /* + * 'idle_cmd_done' is set by AdvISR(). + */ + if (asc_dvc->idle_cmd_done) + { + break; + } + DvcSleepMilliSecond(1); + + /* + * If interrupts were disabled on entry to AdvSendIdleCmd(), + * then they will still be disabled here. Call AdvISR() to + * check for the idle command completion. + */ + (void) AdvISR(asc_dvc); + } + + last_int_level = DvcEnterCritical(); + + if (asc_dvc->idle_cmd_done == ADV_FALSE) + { + ADV_ASSERT(0); /* The idle command should never timeout. */ + return ADV_FALSE; + } else + { + AdvReadWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, ret); + return ret; + } +} + +/* + * Send the SCSI request block to the adapter + * + * Each of the 255 Adv Library/Microcode RISC Lists or mailboxes has the + * following structure: + * + * 0: RQL_FWD - RISC list forward pointer (1 byte) + * 1: RQL_BWD - RISC list backward pointer (1 byte) + * 2: RQL_STATE - RISC list state byte - free, ready, done, aborted (1 byte) + * 3: RQL_TID - request target id (1 byte) + * 4: RQL_PHYADDR - ADV_SCSI_REQ_Q physical pointer (4 bytes) + * + * Return: + * ADV_SUCCESS(1) - the request is in the mailbox + * ADV_BUSY(0) - total request count > 253, try later + */ +STATIC int +AdvSendScsiCmd( + ADV_DVC_VAR *asc_dvc, + ADV_SCSI_REQ_Q *scsiq) +{ + ushort next_ready_loc; + uchar next_ready_loc_fwd; + int last_int_level; + AdvPortAddr iop_base; + long req_size; + ulong q_phy_addr; + + /* + * The ADV_SCSI_REQ_Q 'target_id' field should never be equal + * to the host adapter ID or exceed ADV_MAX_TID. + */ + if (scsiq->target_id == asc_dvc->chip_scsi_id || + scsiq->target_id > ADV_MAX_TID) + { + scsiq->host_status = QHSTA_M_INVALID_DEVICE; + scsiq->done_status = QD_WITH_ERROR; + return ADV_ERROR; + } + + iop_base = asc_dvc->iop_base; + + last_int_level = DvcEnterCritical(); + + if (asc_dvc->cur_host_qng >= asc_dvc->max_host_qng) + { + DvcLeaveCritical(last_int_level); + return ADV_BUSY; + } else + { + ADV_ASSERT(asc_dvc->cur_host_qng < ASC_MC_RISC_Q_TOTAL_CNT); + asc_dvc->cur_host_qng++; + } + + /* + * Clear the ADV_SCSI_REQ_Q done flag. + */ + scsiq->a_flag &= ~ADV_SCSIQ_DONE; + + /* + * Save the original sense buffer length. + * + * After the request completes 'sense_len' will be set to the residual + * byte count of the Auto-Request Sense if a command returns CHECK + * CONDITION and the Sense Data is valid indicated by 'host_status' not + * being set to QHSTA_M_AUTO_REQ_SENSE_FAIL. To determine the valid + * Sense Data Length subtract 'sense_len' from 'orig_sense_len'. + */ + scsiq->orig_sense_len = scsiq->sense_len; + + AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc); + next_ready_loc = ASC_MC_RISC_Q_LIST_BASE + + (next_ready_loc * ASC_MC_RISC_Q_LIST_SIZE); + + /* + * Write the physical address of the Q to the mailbox. + * We need to skip the first four bytes, because the microcode + * uses them internally for linking Q's together. + */ + req_size = sizeof(ADV_SCSI_REQ_Q); + q_phy_addr = DvcGetPhyAddr(asc_dvc, scsiq, + (uchar *) scsiq, &req_size, + ADV_IS_SCSIQ_FLAG); + ADV_ASSERT(ADV_DWALIGN(q_phy_addr) == q_phy_addr); + ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q)); + + scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq; + + /* + * The RISC list structure, which 'next_ready_loc' is a pointer + * to in microcode LRAM, has the format detailed in the comment + * header for this function. + * + * Write the ADV_SCSI_REQ_Q physical pointer to 'next_ready_loc' request. + */ + AdvWriteDWordLram(iop_base, next_ready_loc + RQL_PHYADDR, q_phy_addr); + + /* Write target_id to 'next_ready_loc' request. */ + AdvWriteByteLram(iop_base, next_ready_loc + RQL_TID, scsiq->target_id); + + /* + * Set the ASC_MC_HOST_NEXT_READY (0x128) microcode variable to + * the 'next_ready_loc' request forward pointer. + * + * Do this *before* changing the 'next_ready_loc' queue to QS_READY. + * After the state is changed to QS_READY 'RQL_FWD' will be changed + * by the microcode. + * + * NOTE: The temporary variable 'next_ready_loc_fwd' is required to + * prevent some compilers from optimizing out 'AdvReadByteLram()' if + * it were used as the 3rd argument to 'AdvWriteByteLram()'. + */ + AdvReadByteLram(iop_base, next_ready_loc + RQL_FWD, next_ready_loc_fwd); + AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc_fwd); + + /* + * Change the state of 'next_ready_loc' request from QS_FREE to + * QS_READY which will cause the microcode to pick it up and + * execute it. + * + * Can't reference 'next_ready_loc' after changing the request + * state to QS_READY. The microcode now owns the request. + */ + AdvWriteByteLram(iop_base, next_ready_loc + RQL_STATE, ASC_MC_QS_READY); + + DvcLeaveCritical(last_int_level); + return ADV_SUCCESS; +} + +/* + * Inquiry Information Byte 7 Handling + * + * Handle SCSI Inquiry Command information for a device by setting + * microcode operating variables that affect WDTR, SDTR, and Tag + * Queuing. + */ +STATIC void +AdvInquiryHandling( + ADV_DVC_VAR *asc_dvc, + ADV_SCSI_REQ_Q *scsiq) +{ + AdvPortAddr iop_base; + uchar tid; + ASC_SCSI_INQUIRY *inq; + ushort tidmask; + ushort cfg_word; + + /* + * AdvInquiryHandling() requires up to INQUIRY information Byte 7 + * to be available. + * + * If less than 8 bytes of INQUIRY information were requested or less + * than 8 bytes were transferred, then return. cdb[4] is the request + * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the + * microcode to the transfer residual count. + */ + if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8) + { + return; + } + + iop_base = asc_dvc->iop_base; + tid = scsiq->target_id; + inq = (ASC_SCSI_INQUIRY *) scsiq->vdata_addr; + + /* + * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices. + */ + if (inq->byte3.rsp_data_fmt < 2 && inq->byte2.ansi_apr_ver < 2) + { + return; + } else + { + /* + * INQUIRY Byte 7 Handling + * + * Use a device's INQUIRY byte 7 to determine whether it + * supports WDTR, SDTR, and Tag Queuing. If the feature + * is enabled in the EEPROM and the device supports the + * feature, then enable it in the microcode. + */ + + tidmask = ADV_TID_TO_TIDMASK(tid); + + /* + * Wide Transfers + * + * If the EEPROM enabled WDTR for the device and the device + * supports wide bus (16 bit) transfers, then turn on the + * device's 'wdtr_able' bit and write the new value to the + * microcode. + */ + if ((asc_dvc->wdtr_able & tidmask) && inq->byte7.WBus16) + { + AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); + if ((cfg_word & tidmask) == 0) + { + cfg_word |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); + + /* + * Clear the microcode "WDTR negotiation" done indicator + * for the target to cause it to negotiate with the new + * setting set above. + */ + AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); + cfg_word &= ~tidmask; + AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); + } + } + + /* + * Synchronous Transfers + * + * If the EEPROM enabled SDTR for the device and the device + * supports synchronous transfers, then turn on the device's + * 'sdtr_able' bit. Write the new value to the microcode. + */ + if ((asc_dvc->sdtr_able & tidmask) && inq->byte7.Sync) + { + AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); + if ((cfg_word & tidmask) == 0) + { + cfg_word |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); + + /* + * Clear the microcode "SDTR negotiation" done indicator + * for the target to cause it to negotiate with the new + * setting set above. + */ + AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); + cfg_word &= ~tidmask; + AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); + } + } + + /* + * If the EEPROM enabled Tag Queuing for device and the + * device supports Tag Queuing, then turn on the device's + * 'tagqng_enable' bit in the microcode and set the microcode + * maximum command count to the ADV_DVC_VAR 'max_dvc_qng' + * value. + * + * Tag Queuing is disabled for the BIOS which runs in polled + * mode and would see no benefit from Tag Queuing. Also by + * disabling Tag Queuing in the BIOS devices with Tag Queuing + * bugs will at least work with the BIOS. + */ + if ((asc_dvc->tagqng_able & tidmask) && inq->byte7.CmdQue) + { + AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); + cfg_word |= tidmask; + AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); + AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, + asc_dvc->max_dvc_qng); + } + } } diff -ur --new-file old/linux/drivers/scsi/advansys.h new/linux/drivers/scsi/advansys.h --- old/linux/drivers/scsi/advansys.h Tue Jan 13 01:44:36 1998 +++ new/linux/drivers/scsi/advansys.h Wed Mar 18 06:43:46 1998 @@ -1,9 +1,9 @@ -/* $Id: advansys.h,v 1.6 1997/05/30 19:25:12 davem Exp $ */ +/* $Id: advansys.h,v 1.17 1998/01/08 21:23:49 bobf Exp bobf $ */ /* * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters * - * Copyright (c) 1995-1997 Advanced System Products, Inc. + * Copyright (c) 1995-1998 Advanced System Products, Inc. * All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -18,7 +18,7 @@ * ftp://ftp.advansys.com/pub/linux * * Please send questions, comments, bug reports to: - * bobf@advansys.com (Bob Frey) + * bobf@advansys.com (Bob Frey) */ #ifndef _ADVANSYS_H @@ -40,10 +40,18 @@ int advansys_command(Scsi_Cmnd *); int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int advansys_abort(Scsi_Cmnd *); +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) +int advansys_reset(Scsi_Cmnd *); +#else /* version >= v1.3.89 */ int advansys_reset(Scsi_Cmnd *, unsigned int); +#endif /* version >= v1.3.89 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) +int advansys_biosparam(Disk *, int, int[]); +#else /* version >= v1.3.0 */ int advansys_biosparam(Disk *, kdev_t, int[]); extern struct proc_dir_entry proc_scsi_advansys; int advansys_proc_info(char *, char **, off_t, int, int, int); +#endif /* version >= v1.3.0 */ /* init/main.c setup function */ void advansys_setup(char *, int *); @@ -51,31 +59,116 @@ /* * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h. */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) #define ADVANSYS { \ - proc_dir: &proc_scsi_advansys, \ - proc_info: advansys_proc_info, \ - name: "advansys", \ - detect: advansys_detect, \ - release: advansys_release, \ - info: advansys_info, \ - command: advansys_command, \ - queuecommand: advansys_queuecommand, \ - abort: advansys_abort, \ - reset: advansys_reset, \ - bios_param: advansys_biosparam, \ - /* \ - * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ - * must be set. The flag will be cleared in advansys_detect for non-ISA \ - * adapters. Refer to the comment in scsi_module.c for more information. \ - */ \ - unchecked_isa_dma: 1, \ - /* \ - * All adapters controlled by this driver are capable of large \ - * scatter-gather lists. According to the mid-level SCSI documentation \ - * this obviates any performance gain provided by setting \ - * 'use_clustering'. But empirically while CPU utilization is increased \ - * by enabling clustering, I/O throughput increases as well. \ - */ \ - use_clustering: ENABLE_CLUSTERING, \ + NULL, /* struct SHT *next */ \ + NULL, /* int *usage_count */ \ + "advansys", /* char *name */ \ + advansys_detect, /* int (*detect)(struct SHT *) */ \ + advansys_release, /* int (*release)(struct Scsi_Host *) */ \ + advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ + advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ + advansys_queuecommand, \ + /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ + advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ + advansys_reset, /* int (*reset)(Scsi_Cmnd *) */ \ + NULL, /* int (*slave_attach)(int, int) */ \ + advansys_biosparam, /* int (* bios_param)(Disk *, int, int []) */ \ + /* \ + * The following fields are set per adapter in advansys_detect(). \ + */ \ + 0, /* int can_queue */ \ + 0, /* int this_id */ \ + 0, /* short unsigned int sg_tablesize */ \ + 0, /* short cmd_per_lun */ \ + 0, /* unsigned char present */ \ + /* \ + * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ + * must be set. The flag will be cleared in advansys_detect for non-ISA \ + * adapters. Refer to the comment in scsi_module.c for more information. \ + */ \ + 1, /* unsigned unchecked_isa_dma:1 */ \ + /* \ + * All adapters controlled by this driver are capable of large \ + * scatter-gather lists. According to the mid-level SCSI documentation \ + * this obviates any performance gain provided by setting \ + * 'use_clustering'. But empirically while CPU utilization is increased \ + * by enabling clustering, I/O throughput increases as well. \ + */ \ + ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ } +#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75) +#define ADVANSYS { \ + NULL, /* struct SHT *next */ \ + NULL, \ + /* version < v2.1.23 long *usage_count */ \ + /* version >= v2.1.23 struct module * */ \ + &proc_scsi_advansys, /* struct proc_dir_entry *proc_dir */ \ + advansys_proc_info, \ + /* int (*proc_info)(char *, char **, off_t, int, int, int) */ \ + "advansys", /* const char *name */ \ + advansys_detect, /* int (*detect)(struct SHT *) */ \ + advansys_release, /* int (*release)(struct Scsi_Host *) */ \ + advansys_info, /* const char *(*info)(struct Scsi_Host *) */ \ + advansys_command, /* int (*command)(Scsi_Cmnd *) */ \ + advansys_queuecommand, \ + /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ + advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ + advansys_reset, \ + /* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \ + /* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \ + NULL, /* int (*slave_attach)(int, int) */ \ + advansys_biosparam, /* int (* bios_param)(Disk *, kdev_t, int []) */ \ + /* \ + * The following fields are set per adapter in advansys_detect(). \ + */ \ + 0, /* int can_queue */ \ + 0, /* int this_id */ \ + 0, /* short unsigned int sg_tablesize */ \ + 0, /* short cmd_per_lun */ \ + 0, /* unsigned char present */ \ + /* \ + * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ + * must be set. The flag will be cleared in advansys_detect for non-ISA \ + * adapters. Refer to the comment in scsi_module.c for more information. \ + */ \ + 1, /* unsigned unchecked_isa_dma:1 */ \ + /* \ + * All adapters controlled by this driver are capable of large \ + * scatter-gather lists. According to the mid-level SCSI documentation \ + * this obviates any performance gain provided by setting \ + * 'use_clustering'. But empirically while CPU utilization is increased \ + * by enabling clustering, I/O throughput increases as well. \ + */ \ + ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ +} +#else /* version >= v2.1.75 */ +#define ADVANSYS { \ + proc_dir: &proc_scsi_advansys, \ + proc_info: advansys_proc_info, \ + name: "advansys", \ + detect: advansys_detect, \ + release: advansys_release, \ + info: advansys_info, \ + command: advansys_command, \ + queuecommand: advansys_queuecommand, \ + abort: advansys_abort, \ + reset: advansys_reset, \ + bios_param: advansys_biosparam, \ + /* \ + * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ + * must be set. The flag will be cleared in advansys_detect for non-ISA \ + * adapters. Refer to the comment in scsi_module.c for more information. \ + */ \ + unchecked_isa_dma: 1, \ + /* \ + * All adapters controlled by this driver are capable of large \ + * scatter-gather lists. According to the mid-level SCSI documentation \ + * this obviates any performance gain provided by setting \ + * 'use_clustering'. But empirically while CPU utilization is increased \ + * by enabling clustering, I/O throughput increases as well. \ + */ \ + use_clustering: ENABLE_CLUSTERING, \ +} +#endif /* version >= v2.1.75 */ #endif /* _ADVANSYS_H */ diff -ur --new-file old/linux/drivers/scsi/dc390.h new/linux/drivers/scsi/dc390.h --- old/linux/drivers/scsi/dc390.h Tue Jan 13 01:44:36 1998 +++ new/linux/drivers/scsi/dc390.h Wed Mar 18 06:43:47 1998 @@ -5,19 +5,7 @@ * Bus Master Host Adapter * ***********************************************************************/ -/* Kernel version autodetection */ - #include -/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ -#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) - -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,50) -#define VERSION_ELF_1_2_13 -#elseif LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,95) -#define VERSION_1_3_85 -#else -#define VERSION_2_0_0 -#endif /* * AMD 53C974 driver, header file @@ -28,45 +16,27 @@ #if defined(HOSTS_C) || defined(MODULE) -#ifdef VERSION_2_0_0 #include -#else -#include -#endif extern int DC390_detect(Scsi_Host_Template *psht); extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); extern int DC390_abort(Scsi_Cmnd *cmd); - -#ifdef VERSION_2_0_0 extern int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags); -#else -extern int DC390_reset(Scsi_Cmnd *cmd); -#endif - -#ifdef VERSION_ELF_1_2_13 -extern int DC390_bios_param(Disk *disk, int devno, int geom[]); -#else extern int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]); -#endif #ifdef MODULE static int DC390_release(struct Scsi_Host *); #else -#define DC390_release NULL +# define DC390_release NULL #endif -#ifndef VERSION_ELF_1_2_13 extern struct proc_dir_entry proc_scsi_tmscsim; extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); -#endif - -#ifdef VERSION_2_0_0 #define DC390_T { \ proc_dir: &proc_scsi_tmscsim, \ - proc_info: tmscsim_proc_info, \ - name: "Tekram DC390(T) V1.10 Dec-05-1996",\ + proc_info: tmscsim_proc_info, \ + name: "Tekram DC390(T) V1.12 Feb-25-1998",\ detect: DC390_detect, \ release: DC390_release, \ queuecommand: DC390_queue_command, \ @@ -79,61 +49,6 @@ cmd_per_lun: 2, \ use_clustering: DISABLE_CLUSTERING \ } -#endif - - -#ifdef VERSION_1_3_85 - -#define DC390_T { \ - NULL, /* *next */ \ - NULL, /* *usage_count */ \ - &proc_scsi_tmscsim, /* *proc_dir */ \ - tmscsim_proc_info, /* (*proc_info)() */ \ - "Tekram DC390(T) V1.10 Dec-05-1996", /* *name */ \ - DC390_detect, \ - DC390_release, /* (*release)() */ \ - NULL, /* *(*info)() */ \ - NULL, /* (*command)() */ \ - DC390_queue_command, \ - DC390_abort, \ - DC390_reset, \ - NULL, /* slave attach */\ - DC390_bios_param, \ - 10,/* can queue(-1) */ \ - 7, /* id(-1) */ \ - SG_ALL, \ - 2, /* cmd per lun(2) */ \ - 0, /* present */ \ - 0, /* unchecked isa dma */ \ - DISABLE_CLUSTERING \ - } -#endif - - -#ifdef VERSION_ELF_1_2_13 - -#define DC390_T { \ - NULL, \ - NULL, \ - "Tekram DC390(T) V1.10 Dec-05-1996",\ - DC390_detect, \ - DC390_release, \ - NULL, /* info */ \ - NULL, /* command, deprecated */ \ - DC390_queue_command, \ - DC390_abort, \ - DC390_reset, \ - NULL, /* slave attach */\ - DC390_bios_param, \ - 10,/* can queue(-1) */ \ - 7, /* id(-1) */ \ - 16,/* old (SG_ALL) */ \ - 2, /* cmd per lun(2) */ \ - 0, /* present */ \ - 0, /* unchecked isa dma */ \ - DISABLE_CLUSTERING \ - } -#endif #endif /* defined(HOSTS_C) || defined(MODULE) */ 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 Tue Nov 4 18:17:30 1997 +++ new/linux/drivers/scsi/gdth_proc.c Sat Feb 21 03:55:44 1998 @@ -620,12 +620,12 @@ oldto = scp->timeout; scp->timeout = timeout; if (timeout > 0) { - if (timer_table[SCSI_TIMER].expires == 0) { - timer_table[SCSI_TIMER].expires = jiffies + timeout; - timer_active |= 1 << SCSI_TIMER; + if (timer_table[GDTH_TIMER].expires == 0) { + timer_table[GDTH_TIMER].expires = jiffies + timeout; + timer_active |= 1 << GDTH_TIMER; } else { - if (jiffies + timeout < timer_table[SCSI_TIMER].expires) - timer_table[SCSI_TIMER].expires = jiffies + timeout; + if (jiffies + timeout < timer_table[GDTH_TIMER].expires) + timer_table[GDTH_TIMER].expires = jiffies + timeout; } } diff -ur --new-file old/linux/drivers/scsi/hosts.c new/linux/drivers/scsi/hosts.c --- old/linux/drivers/scsi/hosts.c Mon Dec 22 02:04:49 1997 +++ new/linux/drivers/scsi/hosts.c Mon Jan 26 20:41:04 1998 @@ -503,6 +503,32 @@ return 0; } +/* + * Why is this a seperate function? Because the kernel_thread code + * effectively does a fork, and there is a builtin exit() call when + * the child returns. The difficulty is that scsi_init() is + * marked __initfunc(), which means the memory is unmapped after bootup + * is complete, which means that the thread's exit() call gets wiped. + * + * The lesson is to *NEVER*, *NEVER* call kernel_thread() from an + * __initfunc() function, if that function could ever return. + */ +static void launch_error_handler_thread(struct Scsi_Host * shpnt) +{ + struct semaphore sem = MUTEX_LOCKED; + + shpnt->eh_notify = &sem; + + kernel_thread((int (*)(void *))scsi_error_handler, + (void *) shpnt, 0); + /* + * Now wait for the kernel error thread to initialize itself + * as it might be needed when we scan the bus. + */ + down (&sem); + shpnt->eh_notify = NULL; +} + __initfunc(unsigned int scsi_init(void)) { static int called = 0; @@ -559,18 +585,7 @@ */ if( shpnt->hostt->use_new_eh_code ) { - struct semaphore sem = MUTEX_LOCKED; - - shpnt->eh_notify = &sem; - - kernel_thread((int (*)(void *))scsi_error_handler, - (void *) shpnt, 0); - /* - * Now wait for the kernel error thread to initialize itself - * as it might be needed when we scan the bus. - */ - down (&sem); - shpnt->eh_notify = NULL; + launch_error_handler_thread(shpnt); } } diff -ur --new-file old/linux/drivers/scsi/hosts.h new/linux/drivers/scsi/hosts.h --- old/linux/drivers/scsi/hosts.h Tue Jan 13 01:44:32 1998 +++ new/linux/drivers/scsi/hosts.h Wed Mar 18 06:43:43 1998 @@ -371,7 +371,13 @@ void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *); - unsigned long hostdata[0]; /* Used for storage of host specific stuff */ + /* + * We should ensure that this is aligned, both for better performance + * and also because some compilers (m68k) don't automatically force + * alignment to a 4-byte boundary. + */ + unsigned long hostdata[0] /* Used for storage of host specific stuff */ + __attribute__ ((aligned (sizeof(unsigned long)))); }; extern struct Scsi_Host * scsi_hostlist; diff -ur --new-file old/linux/drivers/scsi/ibmmca.c new/linux/drivers/scsi/ibmmca.c --- old/linux/drivers/scsi/ibmmca.c Sun Nov 30 20:34:27 1997 +++ new/linux/drivers/scsi/ibmmca.c Mon Feb 2 23:51:31 1998 @@ -199,10 +199,11 @@ 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 CONFIG_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. (See also the new Config.in file.) + 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 @@ -210,8 +211,64 @@ 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 - @@ -252,7 +309,12 @@ /*--------------------------------------------------------------------*/ /* current version of this driver-source: */ -#define IBMMCA_SCSI_DRIVER_VERSION "3.0d" +#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. */ /* Driver Description @@ -341,8 +403,23 @@ 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. - + 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(). @@ -443,7 +520,7 @@ /* basic I/O-port of first adapter */ #define IM_IO_PORT 0x3540 -/* maximum number of hosts that can be find */ +/* maximum number of hosts that can be found */ #define IM_N_IO_PORT 8 /*requests going into the upper nibble of the Attention register */ @@ -589,16 +666,19 @@ interest, debugging or just for having fun. The left number gives the host-adapter number and the right shows the accessed SCSI-ID. */ +/* use_display is set by the ibmmcascsi=display command line arg */ +static int use_display = 0; #define PS2_DISK_LED_ON(ad,id) {\ - if( machine_id == 0xf8 ) { outb((char)(id+48), MOD95_LED_PORT ); \ + if( use_display ) { outb((char)(id+48), MOD95_LED_PORT ); \ outb((char)(ad+48), MOD95_LED_PORT+1); } \ else outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \ } +/* bug fixed, Dec 15, 1997, where | was replaced by & here */ #define PS2_DISK_LED_OFF() {\ - if( machine_id == 0xf8 ) { outb( ' ', MOD95_LED_PORT ); \ + if( use_display ) { outb( ' ', MOD95_LED_PORT ); \ outb(' ', MOD95_LED_PORT+1); } \ - else outb(inb(PS2_SYS_CTR) | 0x3f, PS2_SYS_CTR); \ + else outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \ } /*--------------------------------------------------------------------*/ @@ -609,6 +689,8 @@ unsigned short mca_id; char *description; }; + +/* List of possible IBM-SCSI-adapters */ struct subsys_list_struct subsys_list[] = { {0x8efc, "IBM Fast SCSI-2 Adapter"}, @@ -632,14 +714,14 @@ /*local data for a logical device */ struct logical_device { - struct im_scb scb; + struct im_scb scb; /* SCSI-subsystem-control-block structure */ struct im_tsb tsb; struct im_sge sge[16]; Scsi_Cmnd *cmd; /* SCSI-command that is currently in progress */ int device_type; /* type of the SCSI-device. See include/scsi/scsi.h - for interpreation of the possible values */ - int block_length; + for interpretation of the possible values */ + int block_length;/* blocksize of a particular logical SCSI-device */ }; /* statistics of the driver during operations (for proc_info) */ @@ -649,6 +731,8 @@ int ldn_access[MAX_LOG_DEV+1]; /* total accesses on a ldn */ int ldn_read_access[MAX_LOG_DEV+1]; /* total read-access on a ldn */ int ldn_write_access[MAX_LOG_DEV+1]; /* total write-access on a ldn */ + int ldn_inquiry_access[MAX_LOG_DEV+1]; /* total inquiries on a ldn */ + int ldn_modeselect_access[MAX_LOG_DEV+1]; /* total mode selects on ldn */ int total_accesses; /* total accesses on all ldns */ int total_interrupts; /* total interrupts (should be same as total_accesses) */ @@ -663,26 +747,28 @@ /* 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 */ + /* 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 */ + attached to this host adapter: */ unsigned char _get_scsi[8][8]; - /* used only when checking logical devices */ + /* 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) */ + /* reset status (used only when doing reset): */ int _reset_status; - /* code of the last SCSI command (needed for panic info) */ + /* code of the last SCSI command (needed for panic info): */ int _last_scsi_command; - /* counter that points on next reassignable ldn for dynamical remapping */ - /* The default value is 7, that is the first reassignable number in - the list on startup. */ + /* 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 for this IBM-SCSI-host */ + /* Statistics-structure for this IBM-SCSI-host: */ struct Driver_Statistics _IBM_DS; }; @@ -701,21 +787,21 @@ #define IBM_DS (HOSTDATA(shpnt)->_IBM_DS) /* Define a arbitrary number as subsystem-marker-type. This number is, as - described in the SCSI-Standard, not occupied by other device-types. */ + described in the ANSI-SCSI-standard, not occupied by other device-types. */ #define TYPE_IBM_SCSI_ADAPTER 0x2F /* Define 0xFF for no device type, because this type is not defined within - the SCSI-standard, therefore, it can be used and should not cause any + the ANSI-SCSI-standard, therefore, it can be used and should not cause any harm. */ #define TYPE_NO_DEVICE 0xFF -/* define medium-changer. If this is not defined previously, define - this type here. */ +/* define medium-changer. If this is not defined previously, e.g. Linux + 2.0.x, define this type here. */ #ifndef TYPE_MEDIUM_CHANGER #define TYPE_MEDIUM_CHANGER 0x08 #endif -/* define operations for immediate_assign */ +/* define possible operations for the immediate_assign command */ #define SET_LDN 0 #define REMOVE_LDN 1 @@ -732,7 +818,7 @@ static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 }; /* fill module-parameters only, when this define is present. - (that is kernel >=2.1.0) */ + (that is kernel version 2.1.x) */ #ifdef MODULE_PARM MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); @@ -1036,24 +1122,19 @@ return("-"); } -/* type-interpreter for logical devices - (A bit stupid, but it was necessary to get the '-' and the Hex-codes - into one type.) */ +/* interpreter for logical device numbers (ldn) */ static char *ti_l(int value) { - switch (value) - { - case 0: return("0"); break; case 1: return("1"); break; - case 2: return("2"); break; case 3: return("3"); break; - case 4: return("4"); break; case 5: return("5"); break; - case 6: return("6"); break; case 7: return("7"); break; - case 8: return("8"); break; case 9: return("9"); break; - case 10: return("a"); break; case 11: return("b"); break; - case 12: return("c"); break; case 13: return("d"); break; - case 14: return("e"); break; case 15: return("f"); break; - default: return("-"); break; - } - return("-"); + const char hex[16] = ("0123456789abcdef"); + static char answer[2]; + + answer[1] = (char)(0x0); + if (value<=MAX_LOG_DEV) + answer[0] = hex[value]; + else + answer[0] = '-'; + + return (char *)&answer; } /* @@ -1093,7 +1174,7 @@ 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<=7; lun++) /* mark the adapter at its pun on all luns*/ + 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 @@ -1111,13 +1192,13 @@ immediate_assign(shpnt,0,0,ldn,REMOVE_LDN); /* remove ldn (wherever)*/ } - lun = 0; + lun = 0; /* default lun is 0 */ /* STEP 2: */ printk("\nIBM MCA SCSI: Probing SCSI-devices."); - for (id=0; id<=7; id++) + for (id=0; id<8; id++) #ifdef CONFIG_SCSI_MULTI_LUN - for (lun=0; lun<=7; lun++) + for (lun=0; lun<8; lun++) #endif { #ifdef IM_DEBUG_PROBE @@ -1137,16 +1218,16 @@ } } - /* STEP 3: */ + /* STEP 3: */ printk("\nIBM MCA SCSI: Mapping SCSI-devices."); ldn = 0; lun = 0; #ifdef CONFIG_SCSI_MULTI_LUN - for (lun=0; lun<=7 && ldntarget; +#else + int target = cmd->target; +#endif + /*if (target,lun) is NO LUN or not existing at all, return error */ - if ((get_scsi[cmd->target][cmd->lun] == TYPE_NO_LUN)|| - (get_scsi[cmd->target][cmd->lun] == TYPE_NO_DEVICE)) + if ((get_scsi[target][cmd->lun] == TYPE_NO_LUN)|| + (get_scsi[target][cmd->lun] == TYPE_NO_DEVICE)) { cmd->result = DID_NO_CONNECT << 16; done (cmd); @@ -1607,7 +1706,7 @@ } /*if (target,lun) unassigned, do further checks... */ - ldn = get_ldn[cmd->target][cmd->lun]; + 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 */ @@ -1623,7 +1722,7 @@ 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", - cmd->target, cmd->lun); + target, cmd->lun); cmd->result = DID_NO_CONNECT << 16;/* return no connect*/ done (cmd); return 0; @@ -1631,8 +1730,8 @@ } /* unmap non-processing ldn */ - for (id=0; id<=7; id ++) - for (lun=0; lun<=7; lun++) + for (id=0; id<8; id ++) + for (lun=0; lun<8; lun++) { if (get_ldn[id][lun] == next_ldn) { @@ -1645,9 +1744,9 @@ /* 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,cmd->target,cmd->lun,next_ldn,SET_LDN); + immediate_assign(shpnt,target,cmd->lun,next_ldn,SET_LDN); /* map found ldn to pun,lun */ - get_ldn[cmd->target][cmd->lun] = next_ldn; + 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 */ @@ -1668,19 +1767,19 @@ /* 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, cmd->target, cmd->lun); + 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, cmd->target, cmd->lun); + 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; @@ -1729,7 +1828,7 @@ printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn); #endif - /* for specific device debugging: */ + /* for specific device-type debugging: */ #ifdef IM_DEBUG_CMD_SPEC_DEV if (ld[ldn].device_type==IM_DEBUG_CMD_DEVICE) printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", @@ -1794,7 +1893,7 @@ } scb->u2.blk.length = ld[ldn].block_length; if (++disk_rw_in_progress == 1) - PS2_DISK_LED_ON (shpnt->host_no, cmd->target); + PS2_DISK_LED_ON (shpnt->host_no, target); break; /* for other devices, enter here. Other types are not known by @@ -1830,11 +1929,12 @@ /* 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, cmd->target); + 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; @@ -1856,6 +1956,7 @@ /* 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; @@ -1892,10 +1993,16 @@ unsigned int ldn; void (*saved_done) (Scsi_Cmnd *); +#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD + int target = 6 - cmd->target; +#else + int target = cmd->target; +#endif + /*get logical device number, and disable system interrupts */ printk ("IBM MCA SCSI: sending abort to device id=%d lun=%d.\n", - cmd->target, cmd->lun); - ldn = get_ldn[cmd->target][cmd->lun]; + target, cmd->lun); + ldn = get_ldn[target][cmd->lun]; cli (); /*if cmd for this ldn has already finished, no need to abort */ @@ -2027,12 +2134,32 @@ return(a); } +static int ldn_access_total_inquiry(struct Scsi_Host *shpnt) +{ + int a = 0; + int i; + + for (i=0; i<=MAX_LOG_DEV; i++) + a+=IBM_DS.ldn_inquiry_access[i]; + return(a); +} + +static int ldn_access_total_modeselect(struct Scsi_Host *shpnt) +{ + int a = 0; + int i; + + for (i=0; i<=MAX_LOG_DEV; i++) + a+=IBM_DS.ldn_modeselect_access[i]; + return(a); +} + /* routine to display info in the proc-fs-structure (a deluxe feature) */ int ibmmca_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout) { int len=0; - int i,id; + int i,id,lun; struct Scsi_Host *shpnt; for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++); @@ -2047,6 +2174,11 @@ 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 #ifdef CONFIG_SCSI_MULTI_LUN len += sprintf(buffer+len, " Multiple LUN probing.....: Yes\n"); #else @@ -2064,8 +2196,14 @@ IBM_DS.total_accesses); len += sprintf(buffer+len, " Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(shpnt)); + len += sprintf(buffer+len, " Total SCSI Inquiries...: %d\n", + ldn_access_total_inquiry(shpnt)); + 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)); + IBM_DS.total_accesses - ldn_access_total_read_write(shpnt) + - ldn_access_total_modeselect(shpnt) + - ldn_access_total_inquiry(shpnt)); len += sprintf(buffer+len, " Logical-Device-Number (LDN) Access-Statistics:\n"); len += sprintf(buffer+len, " LDN | Accesses [%%] | READ | WRITE | ASSIGNMENTS\n"); @@ -2096,11 +2234,11 @@ 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 %2s %2s %2s %2s %2s %2s %2s %2s\n", - id, ti_l(get_ldn[id][0]), ti_l(get_ldn[id][1]), - ti_l(get_ldn[id][2]), ti_l(get_ldn[id][3]), - ti_l(get_ldn[id][4]), ti_l(get_ldn[id][5]), - ti_l(get_ldn[id][6]), ti_l(get_ldn[id][7])); + + 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,"\n"); } len += sprintf(buffer+len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n"); @@ -2125,3 +2263,6 @@ #endif /*--------------------------------------------------------------------*/ + + + diff -ur --new-file old/linux/drivers/scsi/ibmmca.h new/linux/drivers/scsi/ibmmca.h --- old/linux/drivers/scsi/ibmmca.h Mon Dec 22 02:04:49 1997 +++ new/linux/drivers/scsi/ibmmca.h Fri Feb 13 01:25:04 1998 @@ -19,6 +19,12 @@ extern struct proc_dir_entry proc_scsi_ibmmca; /*initialization for Scsi_host_template type */ +/* + * 2/8/98 + * Note to maintainer of IBMMCA. Do not change this initializer back to + * the old format. Please ask eric@andante.jic.com if you have any questions + * about this, but it will break things in the future. + */ #define IBMMCA { \ proc_dir: &proc_scsi_ibmmca, /*proc_dir*/ \ proc_info: ibmmca_proc_info, /*proc info fn*/ \ @@ -35,6 +41,8 @@ sg_tablesize: 16, /*sg_tablesize*/ \ cmd_per_lun: 1, /*cmd_per_lun*/ \ use_clustering: ENABLE_CLUSTERING /*use_clustering*/ \ - } + } #endif /* _IBMMCA_H */ + + diff -ur --new-file old/linux/drivers/scsi/ncr53c8xx.c new/linux/drivers/scsi/ncr53c8xx.c --- old/linux/drivers/scsi/ncr53c8xx.c Tue Jan 13 00:05:27 1998 +++ new/linux/drivers/scsi/ncr53c8xx.c Mon Mar 16 23:17:29 1998 @@ -9448,7 +9448,7 @@ /* * Try to fix up PCI config according to wished features. */ -#if defined(__i386) && !defined(MODULE) +#if defined(__i386__) && !defined(MODULE) if ((driver_setup.pci_fix_up & 1) && (chip->features & FE_CLSE) && cache_line_size == 0) { #if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75) diff -ur --new-file old/linux/drivers/scsi/pci2000.c new/linux/drivers/scsi/pci2000.c --- old/linux/drivers/scsi/pci2000.c Wed Nov 5 21:59:49 1997 +++ new/linux/drivers/scsi/pci2000.c Fri Feb 13 00:42:55 1998 @@ -653,7 +653,7 @@ #ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = PCI2220I; +Scsi_Host_Template driver_template = PCI2000; #include "scsi_module.c" #endif diff -ur --new-file old/linux/drivers/scsi/pci2000.h new/linux/drivers/scsi/pci2000.h --- old/linux/drivers/scsi/pci2000.h Mon Dec 22 02:04:49 1997 +++ new/linux/drivers/scsi/pci2000.h Mon Jan 26 22:53:52 1998 @@ -209,7 +209,7 @@ queuecommand: Pci2000_QueueCommand, \ abort: Pci2000_Abort, \ reset: Pci2000_Reset, \ - biosparam: Pci2000_BiosParam, \ + bios_param: Pci2000_BiosParam, \ can_queue: 16, \ this_id: -1, \ sg_tablesize: 16, \ diff -ur --new-file old/linux/drivers/scsi/pci2220i.h new/linux/drivers/scsi/pci2220i.h --- old/linux/drivers/scsi/pci2220i.h Mon Dec 22 02:04:49 1997 +++ new/linux/drivers/scsi/pci2220i.h Mon Jan 26 22:53:52 1998 @@ -328,7 +328,7 @@ queuecommand: Pci2220i_QueueCommand, \ abort: Pci2220i_Abort, \ reset: Pci2220i_Reset, \ - biosparam: Pci2220i_BiosParam, \ + bios_param: Pci2220i_BiosParam, \ can_queue: 1, \ this_id: -1, \ sg_tablesize: SG_NONE, \ diff -ur --new-file old/linux/drivers/scsi/pluto.c new/linux/drivers/scsi/pluto.c --- old/linux/drivers/scsi/pluto.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/pluto.c Thu Jan 22 02:04:39 1998 @@ -0,0 +1,313 @@ +/* pluto.c: SparcSTORAGE Array SCSI host adapter driver. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "scsi.h" +#include "hosts.h" +#include "../fc4/fcp_scsi.h" +#include "pluto.h" + +#include + +/* #define PLUTO_DEBUG */ + +#define pluto_printk printk ("PLUTO %s: ", fc->name); printk + +#ifdef PLUTO_DEBUG +#define PLD(x) pluto_printk x; +#define PLND(x) printk ("PLUTO: "); printk x; +#else +#define PLD(x) +#define PLND(x) +#endif + +struct proc_dir_entry proc_scsi_pluto = { + PROC_SCSI_PLUTO, 5, "pluto", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +static struct ctrl_inquiry { + struct Scsi_Host host; + struct pluto pluto; + Scsi_Cmnd cmd; + char inquiry[256]; + fc_channel *fc; +} *fcs __initdata; +static int fcscount __initdata; +static atomic_t fcss __initdata; +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); + +__initfunc(static void pluto_detect_timeout(unsigned long data)) +{ + PLND(("Timeout\n")) + up(&fc_sem); +} + +__initfunc(static void pluto_detect_done(Scsi_Cmnd *SCpnt)) +{ + /* Do nothing */ +} + +__initfunc(static void pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)) +{ + SCpnt->request.rq_status = RQ_SCSI_DONE; + PLND(("Detect done %08lx\n", (long)SCpnt)) + if (atomic_dec_and_test (&fcss)) + up(&fc_sem); +} + +static void pluto_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 SSAs attached to the machine. + To be fast, do it on all online FC channels at the same time. */ +__initfunc(int pluto_detect(Scsi_Host_Template *tpnt)) +{ + int i, retry, nplutos; + fc_channel *fc; + Scsi_Device dev; + + tpnt->proc_dir = &proc_scsi_pluto; + fcscount = 0; + for_each_online_fc_channel(fc) + fcscount++; + PLND(("%d channels online\n", fcscount)) + if (!fcscount) + return 0; + fcs = (struct ctrl_inquiry *) scsi_init_malloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA); + if (!fcs) { + printk ("PLUTO: Not enough memory to probe\n"); + return 0; + } + + memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount); + memset (&dev, 0, sizeof(dev)); + atomic_set (&fcss, fcscount); + fc_timer.function = pluto_detect_timeout; + + i = 0; + for_each_online_fc_channel(fc) { + Scsi_Cmnd *SCpnt; + struct Scsi_Host *host; + struct pluto *pluto; + + if (i == fcscount) break; + + PLD(("trying to find SSA\n")) + + /* If this is already registered to some other SCSI host, then it cannot be pluto */ + if (fc->scsi_name[0]) continue; + memcpy (fc->scsi_name, "SSA", 4); + + fcs[i].fc = fc; + + fc->can_queue = PLUTO_CAN_QUEUE; + fc->rsp_size = 64; + fc->encode_addr = pluto_encode_addr; + + fc->fcp_register(fc, TYPE_SCSI_FCP, 0); + + SCpnt = &(fcs[i].cmd); + host = &(fcs[i].host); + pluto = (struct pluto *)host->hostdata; + + pluto->fc = fc; + + SCpnt->host = host; + SCpnt->cmnd[0] = INQUIRY; + SCpnt->cmnd[4] = 255; + + /* FC layer requires this, so that SCpnt->device->tagged_supported is initially 0 */ + SCpnt->device = &dev; + + SCpnt->cmd_len = COMMAND_SIZE(INQUIRY); + + SCpnt->request.rq_status = RQ_SCSI_BUSY; + + SCpnt->done = pluto_detect_done; + SCpnt->bufflen = 256; + SCpnt->buffer = fcs[i].inquiry; + SCpnt->request_bufflen = 256; + SCpnt->request_buffer = fcs[i].inquiry; + PLD(("set up %d %08lx\n", i, (long)SCpnt)) + i++; + } + + for (retry = 0; retry < 5; retry++) { + for (i = 0; i < fcscount; i++) { + if (!fcs[i].fc) break; + if (fcs[i].cmd.request.rq_status != RQ_SCSI_DONE) { + disable_irq(fcs[i].fc->irq); + PLND(("queuecommand %d %d\n", retry, i)) + fcp_scsi_queuecommand (&(fcs[i].cmd), + pluto_detect_scsi_done); + enable_irq(fcs[i].fc->irq); + } + } + + fc_timer.expires = jiffies + 10 * HZ; + add_timer(&fc_timer); + + down(&fc_sem); + PLND(("Woken up\n")) + if (!atomic_read(&fcss)) + break; /* All fc channels have answered us */ + } + del_timer(&fc_timer); + + PLND(("Finished search\n")) + for (i = 0, nplutos = 0; i < fcscount; i++) { + Scsi_Cmnd *SCpnt; + + if (!(fc = fcs[i].fc)) break; + + SCpnt = &(fcs[i].cmd); + + /* Let FC mid-level free allocated resources */ + SCpnt->done (SCpnt); + + if (!SCpnt->result) { + struct pluto_inquiry *inq; + struct pluto *pluto; + struct Scsi_Host *host; + + inq = (struct pluto_inquiry *)fcs[i].inquiry; + + if ((inq->dtype & 0x1f) == TYPE_PROCESSOR && + !strncmp (inq->vendor_id, "SUN", 3) && + !strncmp (inq->product_id, "SSA", 3)) { + char *p; + long *ages; + + ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL); + if (!ages) continue; + + host = scsi_register (tpnt, sizeof (struct pluto)); + if (!host) panic ("Cannot register PLUTO host\n"); + + nplutos++; + + pluto = (struct pluto *)host->hostdata; + + host->max_id = inq->targets; + host->max_channel = inq->channels; + host->irq = fc->irq; + + host->select_queue_depths = pluto_select_queue_depths; + + fc->channels = inq->channels + 1; + fc->targets = inq->targets; + fc->ages = ages; + memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long)); + + pluto->fc = fc; + memcpy (pluto->rev_str, inq->revision, 4); + pluto->rev_str[4] = 0; + p = strchr (pluto->rev_str, ' '); + if (p) *p = 0; + memcpy (pluto->fw_rev_str, inq->fw_revision, 4); + pluto->fw_rev_str[4] = 0; + p = strchr (pluto->fw_rev_str, ' '); + if (p) *p = 0; + memcpy (pluto->serial_str, inq->serial, 12); + pluto->serial_str[12] = 0; + p = strchr (pluto->serial_str, ' '); + if (p) *p = 0; + + PLD(("Found SSA rev %s fw rev %s serial %s %dx%d\n", pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, host->max_channel, host->max_id)) + } else + fc->fcp_register(fc, TYPE_SCSI_FCP, 1); + } else + fc->fcp_register(fc, TYPE_SCSI_FCP, 1); + } + scsi_init_free((char *)fcs, sizeof (struct ctrl_inquiry) * fcscount); + if (nplutos) + printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos); + return nplutos; +} + +int pluto_release(struct Scsi_Host *host) +{ + struct pluto *pluto = (struct pluto *)host->hostdata; + fc_channel *fc = pluto->fc; + + fc->fcp_register(fc, TYPE_SCSI_FCP, 1); + kfree (fc->ages); + return 0; +} + +const char *pluto_info(struct Scsi_Host *host) +{ + static char buf[80]; + struct pluto *pluto = (struct pluto *) host->hostdata; + + sprintf(buf, "SUN SparcSTORAGE Array %s fw %s serial %s %dx%d on %s", + pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, + host->max_channel, host->max_id, pluto->fc->name); + return buf; +} + +/* SSA uses this FC4S addressing: + switch (addr[0]) + { + case 0: CONTROLLER - All of addr[1]..addr[3] has to be 0 + case 1: SINGLE DISK - addr[1] channel, addr[2] id, addr[3] 0 + case 2: DISK GROUP - ??? + } + + So that SCSI mid-layer can access to these, we reserve + 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) +{ + PLND(("encode addr %d %d %d\n", SCpnt->channel, SCpnt->target, SCpnt->cmnd[1] & 0xe0)) + /* We don't support LUNs */ + if (SCpnt->cmnd[1] & 0xe0) return -EINVAL; + if (!SCpnt->channel) { + if (SCpnt->target) return -EINVAL; + memset (addr, 0, 4 * sizeof(u16)); + } else { + addr[0] = 1; + addr[1] = SCpnt->channel - 1; + addr[2] = SCpnt->target; + addr[3] = 0; + } + PLND(("trying %04x%04x%04x%04x\n", addr[0], addr[1], addr[2], addr[3])) + return 0; +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = PLUTO; + +#include "scsi_module.c" + +EXPORT_NO_SYMBOLS; +#endif /* MODULE */ diff -ur --new-file old/linux/drivers/scsi/pluto.h new/linux/drivers/scsi/pluto.h --- old/linux/drivers/scsi/pluto.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/pluto.h Thu Jan 22 02:04:39 1998 @@ -0,0 +1,59 @@ +/* pluto.h: SparcSTORAGE Array SCSI host adapter driver definitions. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#ifndef _PLUTO_H +#define _PLUTO_H + +#include "../fc4/fcp_scsi.h" + +struct pluto { + /* This must be first */ + fc_channel *fc; + char rev_str[5]; + char fw_rev_str[5]; + char serial_str[13]; +}; + +struct pluto_inquiry { + u8 dtype; + u8 removable:1, qualifier:7; + u8 iso:2, ecma:3, ansi:3; + u8 aenc:1, trmiop:1, :2, rdf:4; + u8 len; + u8 xxx1; + u8 xxx2; + u8 reladdr:1, wbus32:1, wbus16:1, sync:1, linked:1, :1, cmdque:1, softreset:1; + u8 vendor_id[8]; + u8 product_id[16]; + u8 revision[4]; + u8 fw_revision[4]; + u8 serial[12]; + u8 xxx3[2]; + u8 channels; + u8 targets; +}; + +/* This is the max number of outstanding SCSI commands per pluto */ +#define PLUTO_CAN_QUEUE 254 + +int pluto_detect(Scsi_Host_Template *); +int pluto_release(struct Scsi_Host *); +const char * pluto_info(struct Scsi_Host *); + +#define PLUTO { \ + detect: pluto_detect, \ + release: pluto_release, \ + info: pluto_info, \ + queuecommand: fcp_scsi_queuecommand, \ + abort: fcp_scsi_abort, \ + reset: fcp_scsi_reset, \ + can_queue: PLUTO_CAN_QUEUE, \ + this_id: -1, \ + sg_tablesize: 1, \ + cmd_per_lun: 1, \ + use_clustering: ENABLE_CLUSTERING \ +} + +#endif /* !(_PLUTO_H) */ diff -ur --new-file old/linux/drivers/scsi/ppa.c new/linux/drivers/scsi/ppa.c --- old/linux/drivers/scsi/ppa.c Sat Nov 22 19:28:31 1997 +++ new/linux/drivers/scsi/ppa.c Tue Mar 10 23:43:13 1998 @@ -50,8 +50,8 @@ #include "ppa.h" #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #ifndef PARPORT_MODULES #define PARPORT_MODULES "parport_pc" #endif @@ -130,7 +130,7 @@ nhosts = 0; try_again = 0; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (!pb) { request_module(PARPORT_MODULES); pb = parport_enumerate(); diff -ur --new-file old/linux/drivers/scsi/ppa.h new/linux/drivers/scsi/ppa.h --- old/linux/drivers/scsi/ppa.h Tue Jan 13 01:44:36 1998 +++ new/linux/drivers/scsi/ppa.h Wed Mar 18 06:43:47 1998 @@ -15,6 +15,7 @@ /* Use the following to enable certain chipset support * Default is PEDANTIC = 3 */ +#include /* for CONFIG_SCSI_PPA_HAVE_PEDANTIC */ #ifndef CONFIG_SCSI_PPA_HAVE_PEDANTIC #define CONFIG_SCSI_PPA_HAVE_PEDANTIC 3 #endif diff -ur --new-file old/linux/drivers/scsi/psi240i.h new/linux/drivers/scsi/psi240i.h --- old/linux/drivers/scsi/psi240i.h Mon Dec 22 02:04:49 1997 +++ new/linux/drivers/scsi/psi240i.h Mon Jan 26 22:53:52 1998 @@ -327,7 +327,7 @@ queuecommand: Psi240i_QueueCommand, \ abort: Psi240i_Abort, \ reset: Psi240i_Reset, \ - biosparam: Psi240i_BiosParam, \ + bios_param: Psi240i_BiosParam, \ can_queue: 1, \ this_id: -1, \ sg_tablesize: SG_NONE, \ diff -ur --new-file old/linux/drivers/scsi/scsi.c new/linux/drivers/scsi/scsi.c --- old/linux/drivers/scsi/scsi.c Sun Jan 4 19:55:09 1998 +++ new/linux/drivers/scsi/scsi.c Thu Mar 12 00:07:43 1998 @@ -23,10 +23,13 @@ * Added request_module("scsi_hostadapter") for kerneld: * (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules) * Bjorn Ekwall + * (changed to kmod) * * Major improvements to the timeout, abort, and reset processing, * as well as performance modifications for large queue depths by * Leonard N. Zubkoff + * + * Converted cli() code to spinlocks, Ingo Molnar */ #include @@ -51,13 +54,14 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" #include "constants.h" -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif #undef USE_STATIC_SCSI_MEMORY @@ -122,6 +126,8 @@ 12, 12, 10, 10 }; static unsigned long serial_number = 0; static Scsi_Cmnd * scsi_bh_queue_head = NULL; +static Scsi_Cmnd * scsi_bh_queue_tail = NULL; +static spinlock_t scsi_bh_queue_spin = SPIN_LOCK_UNLOCKED; static FreeSectorBitmap * dma_malloc_freelist = NULL; static int need_isa_bounce_buffers; static unsigned int dma_sectors = 0; @@ -200,16 +206,6 @@ static void scsi_dump_status(int level); -/* - * This is the number of clock ticks we should wait before we time out - * and abort the command. This is for where the scsi.c module generates - * the command, not where it originates from a higher level, in which - * case the timeout is specified there. - * - */ - - - struct dev_info{ const char * vendor; const char * model; @@ -224,6 +220,7 @@ */ static struct dev_info device_list[] = { +{"Aashima","IMAGERY 2400SP","1.03",BLIST_NOLUN},/* Locks up if polled for lun != 0 */ {"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */ {"DENON","DRD-25X","V", BLIST_NOLUN}, /* Locks up if probed for lun != 0 */ @@ -356,8 +353,8 @@ * (DB, 4 Feb 1995) */ - save_flags(flags); - cli(); + + spin_lock_irqsave(&io_request_lock, flags); host_active = NULL; for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) { @@ -389,7 +386,7 @@ sh[index]->host_no); } - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); } static void scan_scsis_done (Scsi_Cmnd * SCpnt) @@ -1136,21 +1133,21 @@ SCpnt = found; } - save_flags(flags); - cli(); + __save_flags(flags); + __cli(); /* See if this request has already been queued by an interrupt routine */ if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) { - restore_flags(flags); + __restore_flags(flags); return NULL; } if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) /* Might have changed */ { if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){ sleep_on(&device->device_wait); - restore_flags(flags); + __restore_flags(flags); } else { - restore_flags(flags); + __restore_flags(flags); if (!wait) return NULL; if (!SCwait) { printk("Attempt to allocate device channel %d," @@ -1200,7 +1197,7 @@ * to complete */ } atomic_inc(&SCpnt->host->host_active); - restore_flags(flags); + __restore_flags(flags); SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target, atomic_read(&SCpnt->host->host_active))); @@ -1297,8 +1294,7 @@ host = SCpnt->host; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); /* Assign a unique nonzero serial_number. */ if (++serial_number == 0) serial_number = 1; SCpnt->serial_number = serial_number; @@ -1308,6 +1304,8 @@ * we can avoid the drive not being ready. */ timeout = host->last_reset + MIN_RESET_DELAY; + spin_unlock(&io_request_lock); + if (jiffies < timeout) { int ticks_remaining = timeout - jiffies; /* @@ -1319,11 +1317,11 @@ * interrupt handler (assuming there is one irq-level per * host). */ - sti(); + __sti(); while (--ticks_remaining >= 0) udelay(1000000/HZ); host->last_reset = jiffies - MIN_RESET_DELAY; } - restore_flags(flags); + __restore_flags(flags); /* this possibly puts us back into __cli() */ if( host->hostt->use_new_eh_code ) { @@ -1454,21 +1452,20 @@ * ourselves. */ - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); SCpnt->pid = scsi_pid++; while (SCSI_BLOCK((Scsi_Device *) NULL, host)) { - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host)); - cli(); + spin_lock_irqsave(&io_request_lock, flags); } if (host->block) host_active = host; host->host_busy++; device->device_busy++; - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); /* * Our own function scsi_done (which marks the host as not busy, disables @@ -1533,7 +1530,6 @@ scsi_done (Scsi_Cmnd * SCpnt) { unsigned long flags; - Scsi_Cmnd * SCswap; /* * We don't have to worry about this one timing out any more. @@ -1561,35 +1557,20 @@ * If it was NULL before, then everything is fine, and we are done * (this is the normal case). If it was not NULL, then we block interrupts, * and link them together. + * We need a spinlock here, or compare and exchange if we can reorder incoming + * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times + * before bh is serviced. -jj */ - - SCswap = (Scsi_Cmnd *) xchg(&scsi_bh_queue_head, SCpnt); - if( SCswap != NULL ) - { - /* - * If we assume that the interrupt handler doesn't dawdle, then it is safe to - * say that we should come in here extremely rarely. Under very heavy load, - * the requests might not be removed from the list fast enough so that we - * *do* end up stacking them, and that would be bad. - */ - save_flags(flags); - cli(); - - /* - * See if the pointer is NULL - it might have been serviced already - */ - if( scsi_bh_queue_head == NULL ) - { - scsi_bh_queue_head = SCswap; - } - else - { - SCswap->bh_next = scsi_bh_queue_head; - scsi_bh_queue_head = SCswap; - } - - restore_flags(flags); + + spin_lock_irqsave(&scsi_bh_queue_spin, flags); + if (!scsi_bh_queue_head) { + scsi_bh_queue_head = SCpnt; + scsi_bh_queue_tail = SCpnt; + } else { + scsi_bh_queue_tail->bh_next = SCpnt; + scsi_bh_queue_tail = SCpnt; } + spin_unlock_irqrestore(&scsi_bh_queue_spin, flags); /* * Mark the bottom half handler to be run. @@ -1613,7 +1594,7 @@ Scsi_Cmnd * SCpnt; Scsi_Cmnd * SCnext; static atomic_t recursion_depth; - + unsigned long flags; while(1==1) { @@ -1632,15 +1613,17 @@ } /* - * This is an atomic operation - swap the pointer with a NULL pointer + * We need to hold the spinlock, so that nobody is tampering with the queue. -jj * We will process everything we find in the list here. */ - SCpnt = xchg(&scsi_bh_queue_head, NULL); + + spin_lock_irqsave(&scsi_bh_queue_spin, flags); + SCpnt = scsi_bh_queue_head; + scsi_bh_queue_head = NULL; + spin_unlock_irqrestore(&scsi_bh_queue_spin, flags); if( SCpnt == NULL ) - { return; - } atomic_inc(&recursion_depth); @@ -1836,8 +1819,7 @@ if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE) return NULL; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); nbits = len >> 9; mask = (1 << nbits) - 1; @@ -1845,7 +1827,7 @@ for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){ if ((dma_malloc_freelist[i] & (mask << j)) == 0){ dma_malloc_freelist[i] |= (mask << j); - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); scsi_dma_free_sectors -= nbits; #ifdef DEBUG SCSI_LOG_MLQUEUE(3,printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9))); @@ -1854,7 +1836,7 @@ return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9)); } } - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return NULL; /* Nope. No more */ } @@ -1888,19 +1870,20 @@ if ((mask << sector) >= (1 << SECTORS_PER_PAGE)) panic ("scsi_free:Bad memory alignment"); - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); if((dma_malloc_freelist[page] & (mask << sector)) != (mask<online; SDpnt->online = FALSE; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); if(SCpnt->request.rq_status != RQ_INACTIVE) { - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); printk("SCSI device not inactive - state=%d, id=%d\n", SCpnt->request.rq_status, SCpnt->target); for(SDpnt1 = shpnt->host_queue; SDpnt1; @@ -2850,7 +2830,7 @@ */ SCpnt->state = SCSI_STATE_DISCONNECTING; SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */ - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); } } } @@ -3135,7 +3115,7 @@ /* Load upper level device handler of some kind */ case MODULE_SCSI_DEV: -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (scsi_hosts == NULL) request_module("scsi_hostadapter"); #endif @@ -3209,7 +3189,7 @@ printk(" %d %d %d : %d %p\n", shpnt->host_failed, shpnt->host_busy, - shpnt->host_active, + atomic_read(&shpnt->host_active), shpnt->host_blocked, shpnt->pending_commands); diff -ur --new-file old/linux/drivers/scsi/scsi.h new/linux/drivers/scsi/scsi.h --- old/linux/drivers/scsi/scsi.h Tue Jan 13 01:44:32 1998 +++ new/linux/drivers/scsi/scsi.h Wed Mar 18 06:43:43 1998 @@ -15,6 +15,8 @@ #ifndef _SCSI_H #define _SCSI_H +#include /* for CONFIG_SCSI_LOGGING */ + /* * Some of the public constants are being moved to this file. * We include it here so that what came from where is transparent. @@ -685,7 +687,7 @@ #define INIT_SCSI_REQUEST \ if (!CURRENT) { \ CLEAR_INTR; \ - restore_flags(flags); \ + spin_unlock_irqrestore(&io_request_lock,flags); \ return; \ } \ if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \ 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 Fri Jan 9 05:35:43 1998 +++ new/linux/drivers/scsi/scsi_error.c Thu Mar 12 19:33:21 1998 @@ -8,7 +8,6 @@ * */ -#include #define __NO_VERSION__ #include @@ -37,10 +36,6 @@ #include "constants.h" #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) - -#ifdef CONFIG_KERNELD -#include -#endif #ifdef DEBUG #define SENSE_TIMEOUT SCSI_TIMEOUT diff -ur --new-file old/linux/drivers/scsi/scsi_obsolete.c new/linux/drivers/scsi/scsi_obsolete.c --- old/linux/drivers/scsi/scsi_obsolete.c Fri Jan 9 05:35:43 1998 +++ new/linux/drivers/scsi/scsi_obsolete.c Thu Mar 12 19:33:21 1998 @@ -20,10 +20,6 @@ * Native multichannel, wide scsi, /proc/scsi and hot plugging * support added by Michael Neuffer * - * Added request_module("scsi_hostadapter") for kerneld: - * (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules) - * Bjorn Ekwall - * * Major improvements to the timeout, abort, and reset processing, * as well as performance modifications for large queue depths by * Leonard N. Zubkoff @@ -68,10 +64,6 @@ #include "scsi.h" #include "hosts.h" #include "constants.h" - -#ifdef CONFIG_KERNELD -#include -#endif #undef USE_STATIC_SCSI_MEMORY diff -ur --new-file old/linux/drivers/scsi/scsi_proc.c new/linux/drivers/scsi/scsi_proc.c --- old/linux/drivers/scsi/scsi_proc.c Mon Dec 22 02:04:49 1997 +++ new/linux/drivers/scsi/scsi_proc.c Sat Feb 21 03:28:22 1998 @@ -16,6 +16,7 @@ * Michael A. Griffith */ +#include /* for CONFIG_PROC_FS */ #define __NO_VERSION__ #include @@ -291,7 +292,7 @@ *size = y; return; } -#endif /* CONFIG_SCSI_PROC */ +#endif /* CONFIG_PROC_FS */ /* * Overrides for Emacs so that we get a uniform tabbing style. diff -ur --new-file old/linux/drivers/scsi/scsi_queue.c new/linux/drivers/scsi/scsi_queue.c --- old/linux/drivers/scsi/scsi_queue.c Mon Dec 22 02:04:49 1997 +++ new/linux/drivers/scsi/scsi_queue.c Thu Mar 12 19:33:21 1998 @@ -10,7 +10,6 @@ * we attempt to remove commands from the queue and retry them. */ -#include #define __NO_VERSION__ #include @@ -37,10 +36,6 @@ #include "scsi.h" #include "hosts.h" #include "constants.h" - -#ifdef CONFIG_KERNELD -#include -#endif /* * TODO: diff -ur --new-file old/linux/drivers/scsi/scsiiom.c new/linux/drivers/scsi/scsiiom.c --- old/linux/drivers/scsi/scsiiom.c Wed May 14 07:41:13 1997 +++ new/linux/drivers/scsi/scsiiom.c Thu Feb 26 04:50:22 1998 @@ -175,13 +175,8 @@ } -#ifndef VERSION_ELF_1_2_13 static void DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) -#else -static void -DC390_Interrupt( int irq, struct pt_regs *regs) -#endif { PACB pACB; PDCB pDCB; @@ -303,11 +298,7 @@ pSRB->pSegmentList++; psgl = pSRB->pSegmentList; -#ifndef VERSION_ELF_1_2_13 pSRB->SGPhysAddr = virt_to_phys( psgl->address ); -#else - pSRB->SGPhysAddr = (ULONG) psgl->address; -#endif pSRB->SGToBeXferLen = (ULONG) psgl->length; } else @@ -368,11 +359,7 @@ pSRB->pSegmentList++; psgl = pSRB->pSegmentList; -#ifndef VERSION_ELF_1_2_13 pSRB->SGPhysAddr = virt_to_phys( psgl->address ); -#else - pSRB->SGPhysAddr = (ULONG) psgl->address; -#endif pSRB->SGToBeXferLen = (ULONG) psgl->length; } else @@ -427,11 +414,7 @@ if( residual ) { bval = inb(ioport+ScsiFifo); /* get residual byte */ -#ifndef VERSION_ELF_1_2_13 ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr ); -#else - ptr = (PUCHAR) pSRB->SGPhysAddr; -#endif *ptr = bval; pSRB->SGPhysAddr++; pSRB->TotalXferredLen++; @@ -643,11 +626,7 @@ if( !pSRB->SGToBeXferLen ) { psgl = pSRB->pSegmentList; -#ifndef VERSION_ELF_1_2_13 pSRB->SGPhysAddr = virt_to_phys( psgl->address ); -#else - pSRB->SGPhysAddr = (ULONG) psgl->address; -#endif pSRB->SGToBeXferLen = (ULONG) psgl->length; } lval = pSRB->SGToBeXferLen; diff -ur --new-file old/linux/drivers/scsi/sd.c new/linux/drivers/scsi/sd.c --- old/linux/drivers/scsi/sd.c Sat Jan 10 19:50:07 1998 +++ new/linux/drivers/scsi/sd.c Thu Mar 12 00:07:43 1998 @@ -91,7 +91,7 @@ { if( disknum <= 26 ) { - sprintf(buffer, "sd%c", 'a' + (disknum >> 4)); + sprintf(buffer, "sd%c", 'a' + disknum); } else { @@ -101,8 +101,8 @@ * For larger numbers of disks, we need to go to a new * naming scheme. */ - min1 = (disknum >> 4) / 26; - min2 = (disknum >> 4) % 26; + min1 = disknum / 26; + min2 = disknum % 26; sprintf(buffer, "sd%c%c", 'a' + min1, 'a' + min2); } } @@ -516,11 +516,11 @@ unsigned long flags; int flag = 0; - save_flags(flags); while (1==1){ - cli(); + spin_lock_irqsave(&io_request_lock, flags); + if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -535,6 +535,7 @@ */ if( SDev->host->in_recovery ) { + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -554,6 +555,7 @@ */ if( SDev->removable && !in_interrupt() ) { + spin_unlock_irqrestore(&io_request_lock, flags); scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); /* scsi_ioctl may allow CURRENT to change, so start over. */ SDev->was_reset = 0; @@ -585,7 +587,7 @@ * Using a "sti()" gets rid of the latency problems but causes * race conditions and crashes. */ - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); /* This is a performance enhancement. We dig down into the request * list and try to find a queueable request (i.e. device not busy, @@ -603,7 +605,7 @@ if (!SCpnt && sd_template.nr_dev > 1){ struct request *req1; req1 = NULL; - cli(); + spin_lock_irqsave(&io_request_lock, flags); req = CURRENT; while(req){ SCpnt = scsi_request_queueable(req, @@ -618,7 +620,7 @@ else req1->next = req->next; } - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); } if (!SCpnt) return; /* Could not find anything to do */ @@ -1596,15 +1598,14 @@ target = DEVICE_NR(dev); gdev = &GENDISK_STRUCT; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); if (DEVICE_BUSY || USAGE > maxusage) { - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); printk("Device busy for revalidation (usage=%d)\n", USAGE); return -EBUSY; } DEVICE_BUSY = 1; - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); max_p = gdev->max_p; start = target << gdev->minor_shift; diff -ur --new-file old/linux/drivers/scsi/sg.c new/linux/drivers/scsi/sg.c --- old/linux/drivers/scsi/sg.c Mon Dec 22 02:04:49 1997 +++ new/linux/drivers/scsi/sg.c Fri Feb 27 04:55:28 1998 @@ -547,8 +547,8 @@ struct scsi_generic *device = &scsi_generics[dev]; unsigned int mask = 0; - poll_wait(&scsi_generics[dev].read_wait, wait); - poll_wait(&scsi_generics[dev].write_wait, wait); + 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) diff -ur --new-file old/linux/drivers/scsi/sr.c new/linux/drivers/scsi/sr.c --- old/linux/drivers/scsi/sr.c Fri Jan 9 05:35:43 1998 +++ new/linux/drivers/scsi/sr.c Sat Feb 21 21:34:38 1998 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -432,10 +431,10 @@ int flag = 0; while (1==1){ - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); + if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) { - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); return; }; @@ -451,6 +450,7 @@ */ if( SDev->host->in_recovery ) { + spin_unlock_irqrestore(&io_request_lock, flags); return; } @@ -469,7 +469,11 @@ */ if( SDev->removable && !in_interrupt() ) { + spin_unlock_irqrestore(&io_request_lock, flags); scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); + /* scsi_ioctl may allow CURRENT to change, so start over. */ + SDev->was_reset = 0; + continue; } SDev->was_reset = 0; } @@ -489,7 +493,7 @@ SCpnt = scsi_allocate_device(&CURRENT, scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); else SCpnt = NULL; - restore_flags(flags); + spin_unlock_irqrestore(&io_request_lock, flags); /* This is a performance enhancement. We dig down into the request list and * try to find a queueable request (i.e. device not busy, and host able to @@ -501,8 +505,7 @@ if (!SCpnt && sr_template.nr_dev > 1){ struct request *req1; req1 = NULL; - save_flags(flags); - cli(); + spin_lock_irqsave(&io_request_lock, flags); req = CURRENT; while(req){ SCpnt = scsi_request_queueable(req, @@ -510,15 +513,15 @@ if(SCpnt) break; req1 = req; req = req->next; - }; + } if (SCpnt && req->rq_status == RQ_INACTIVE) { if (req == CURRENT) CURRENT = CURRENT->next; else req1->next = req->next; - }; - restore_flags(flags); - }; + } + spin_unlock_irqrestore(&io_request_lock, flags); + } if (!SCpnt) return; /* Could not find anything to do */ @@ -527,7 +530,7 @@ /* Queue command */ requeue_sr_request(SCpnt); - }; /* While */ + } /* While */ } void requeue_sr_request (Scsi_Cmnd * SCpnt) @@ -761,7 +764,13 @@ if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2; - if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten) + /* + * Note: The scsi standard says that READ_6 is *optional*, while + * READ_10 is mandatory. Thus there is no point in using + * READ_6. + */ + if (scsi_CDs[dev].ten) + { if (realcount > 0xffff) { 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 Fri Jan 9 05:35:43 1998 +++ new/linux/drivers/scsi/sr_ioctl.c Tue Feb 10 01:12:55 1998 @@ -803,6 +803,15 @@ RO_IOCTLS(cdi->dev,arg); + case BLKFLSBUF: + if(!suser()) + return -EACCES; + if(!(cdi->dev)) + return -EINVAL; + fsync_dev(cdi->dev); + invalidate_buffers(cdi->dev); + return 0; + default: return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) 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 Fri Jan 9 05:35:43 1998 +++ new/linux/drivers/scsi/sr_vendor.c Tue Feb 10 01:12:55 1998 @@ -3,7 +3,7 @@ * vendor-specific code for SCSI CD-ROM's goes here. * * This is needed becauce most of the new features (multisession and - * the like) are to new to be included into the SCSI-II standard (to + * the like) are too new to be included into the SCSI-II standard (to * be exact: there is'nt anything in my draft copy). * * Aug 1997: Ha! Got a SCSI-3 cdrom spec across my fingers. SCSI-3 does @@ -83,7 +83,13 @@ if (!strncmp (model,"CD-ROM DRIVE:25", 15) || !strncmp (model,"CD-ROM DRIVE:36", 15) || !strncmp (model,"CD-ROM DRIVE:83", 15) || - !strncmp (model,"CD-ROM DRIVE:84 ",16)) + !strncmp (model,"CD-ROM DRIVE:84 ",16) +#if 0 + /* my NEC 3x returns the read-raw data if a read-raw + is followed by a read for the same sector - aeb */ + || !strncmp (model,"CD-ROM DRIVE:500",16) +#endif + ) /* these can't handle multisession, may hang */ scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION; @@ -145,10 +151,10 @@ int sr_cd_check(struct cdrom_device_info *cdi) { - unsigned long sector,min,sec,frame; + unsigned long sector; unsigned char *buffer; /* the buffer for the ioctl */ unsigned char cmd[12]; /* the scsi-command */ - int rc,is_xa,no_multi,minor; + int rc,no_multi,minor; minor = MINOR(cdi->dev); if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION) @@ -158,7 +164,6 @@ if(!buffer) return -ENOMEM; sector = 0; /* the multisession sector offset goes here */ - is_xa = 0; /* flag: the CD uses XA-Sectors */ no_multi = 0; /* flag: the drive can't handle multisession */ rc = 0; @@ -188,7 +193,8 @@ break; #ifdef CONFIG_BLK_DEV_SR_VENDOR - case VENDOR_NEC: + case VENDOR_NEC: { + unsigned long min,sec,frame; memset(cmd,0,12); cmd[0] = 0xde; cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03; @@ -207,8 +213,11 @@ frame = BCD_TO_BIN(buffer[17]); sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame; break; + } + + case VENDOR_TOSHIBA: { + unsigned long min,sec,frame; - case VENDOR_TOSHIBA: /* we request some disc information (is it a XA-CD ?, * where starts the last session ?) */ memset(cmd,0,12); @@ -230,6 +239,7 @@ if (sector) sector -= CD_MSF_OFFSET; break; + } case VENDOR_WRITER: memset(cmd,0,12); diff -ur --new-file old/linux/drivers/scsi/st.c new/linux/drivers/scsi/st.c --- old/linux/drivers/scsi/st.c Mon Dec 22 22:47:24 1997 +++ new/linux/drivers/scsi/st.c Sun Mar 1 23:46:04 1998 @@ -2846,11 +2846,18 @@ } } - i = flush_buffer(inode, file, /* mtc.mt_op == MTSEEK || */ - mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || - mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || - mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || - mtc.mt_op == MTCOMPRESSION); + if (mtc.mt_op == MTSEEK) { + /* Old position must be restored if partition will be changed */ + i = !STp->can_partitions || + (STp->new_partition != STp->partition); + } + else { + i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || + mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || + mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || + mtc.mt_op == MTCOMPRESSION; + } + i = flush_buffer(inode, file, i); if (i < 0) return i; } diff -ur --new-file old/linux/drivers/scsi/t128.c new/linux/drivers/scsi/t128.c --- old/linux/drivers/scsi/t128.c Sun Jan 4 19:55:09 1998 +++ new/linux/drivers/scsi/t128.c Sat Jan 24 02:38:04 1998 @@ -141,11 +141,11 @@ #define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override)) static struct base { - unsigned char *address; + unsigned int address; int noauto; } bases[] __initdata = { - {(unsigned char *) 0xcc000, 0}, {(unsigned char *) 0xc8000, 0}, - {(unsigned char *) 0xdc000, 0}, {(unsigned char *) 0xd8000, 0}}; + { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0} +}; #define NO_BASES (sizeof (bases) / sizeof (struct base)) @@ -178,7 +178,7 @@ overrides[commandline_current].address = (unsigned char *) ints[1]; overrides[commandline_current].irq = ints[2]; for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == (unsigned char *) ints[1]) { + if (bases[i].address == ints[1]) { bases[i].noauto = 1; break; } @@ -216,7 +216,7 @@ else for (; !base && (current_base < NO_BASES); ++current_base) { #if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : probing address %08x\n", (unsigned int) bases[current_base].address); + printk("scsi-t128 : probing address %08x\n", bases[current_base].address); #endif for (sig = 0; sig < NO_SIGNATURES; ++sig) if (!bases[current_base].noauto && @@ -224,7 +224,7 @@ signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) { - base = bases[current_base].address; + base = (unsigned char *) bases[current_base].address; #if (TDEBUG & TDEBUG_INIT) printk("scsi-t128 : detected board.\n"); #endif diff -ur --new-file old/linux/drivers/scsi/tmscsim.c new/linux/drivers/scsi/tmscsim.c --- old/linux/drivers/scsi/tmscsim.c Thu Jul 10 16:55:30 1997 +++ new/linux/drivers/scsi/tmscsim.c Thu Feb 26 04:50:22 1998 @@ -24,6 +24,9 @@ * 1.09 11/30/96 KG Added register the allocated IO space * * 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset * * pending interrupt in DC390_detect() * + * 1.11 02/05/97 KG/CLH Fixeds problem with partitions greater * + * than 1GB * + * 1.12 25/02/98 KG Cleaned up ifdefs for 2.1 kernel * ***********************************************************************/ @@ -32,7 +35,7 @@ #define SCSI_MALLOC #ifdef MODULE -#include +# include #endif #include @@ -677,11 +680,11 @@ sectors = 32; cylinders = disk->capacity / (heads * sectors); - if ( cylinders > 1024) + if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) ) { heads = 255; sectors = 63; - cylinders = disk->capacity / (255 * 63); + cylinders = disk->capacity / (heads * sectors); } geom[0] = heads; @@ -898,11 +901,7 @@ * Returns : 0 on success. ***********************************************************************/ -#ifdef VERSION_2_0_0 int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) -#else -int DC390_reset (Scsi_Cmnd *cmd) -#endif { USHORT ioport; unsigned long flags; @@ -1161,7 +1160,7 @@ if( !used_irq ) { - if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL)) + if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL)) { printk("DC390: register IRQ error!\n"); return( -1 ); @@ -1763,11 +1762,11 @@ if (acbpnt == (PACB)-1) return(-ESRCH); if(!shpnt) return(-ESRCH); - if(inout) // Has data been written to the file ? + if(inout) /* Has data been written to the file ? */ return(tmscsim_set_info(buffer, length, shpnt)); SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, "); - SPRINTF("Driver Version 1.10, 1996/12/05\n"); + SPRINTF("Driver Version 1.12, 1998/02/25\n"); save_flags(flags); cli(); diff -ur --new-file old/linux/drivers/scsi/tmscsim.h new/linux/drivers/scsi/tmscsim.h --- old/linux/drivers/scsi/tmscsim.h Wed May 14 07:41:13 1997 +++ new/linux/drivers/scsi/tmscsim.h Thu Feb 26 04:50:22 1998 @@ -4,8 +4,8 @@ ;* Device Driver * ;***********************************************************************/ -#ifndef TMSCSIM_H -#define TMSCSIM_H +#ifndef _TMSCSIM_H +#define _TMSCSIM_H #define IRQ_NONE 255 @@ -677,4 +677,4 @@ (PCI_CFG2_ENABLE | (((function) << 1) & 0xe)) -#endif /* TMSCSIM_H */ +#endif /* _TMSCSIM_H */ diff -ur --new-file old/linux/drivers/scsi/wd7000.c new/linux/drivers/scsi/wd7000.c --- old/linux/drivers/scsi/wd7000.c Sun Jan 4 19:55:09 1998 +++ new/linux/drivers/scsi/wd7000.c Tue Mar 10 19:20:58 1998 @@ -127,6 +127,19 @@ * * Thanks to Roger Scott for driver debugging. * + * 06/07/1997 + * + * Added support for /proc file system (/proc/scsi/wd7000/[0...] files). + * Now, driver can handle hard disks with capacity >1GB. + * + * 01/15/1998 + * + * Added support for BUS_ON and BUS_OFF parameters in config line. + * Miscellaneous cleanup. + * + * 03/01/1998 + * + * WD7000 driver now work on kernels >= 2.1.x */ #ifdef MODULE @@ -143,24 +156,29 @@ #include #include #include -#include #include #include #include +#include #include "scsi.h" #include "hosts.h" #include "sd.h" +#include #define ANY2SCSI_INLINE /* undef this to use old macros */ -#undef DEBUG +#undef WD7000_DEBUG /* general debug */ #include "wd7000.h" +#include -#include -struct proc_dir_entry proc_scsi_wd7000 = { - PROC_SCSI_7000FASST, 6, "wd7000", - S_IFDIR | S_IRUGO | S_IXUGO, 2 +struct proc_dir_entry proc_scsi_wd7000 = +{ + PROC_SCSI_7000FASST, + 6, + "wd7000", + S_IFDIR | S_IRUGO | S_IXUGO, + 2 }; @@ -186,52 +204,48 @@ * WD7000-specific mailbox structure * */ -typedef volatile struct mailbox{ - unchar status; - unchar scbptr[3]; /* SCSI-style - MSB first (big endian) */ +typedef volatile struct mailbox { + unchar status; + unchar scbptr[3]; /* SCSI-style - MSB first (big endian) */ } Mailbox; /* * This structure should contain all per-adapter global data. I.e., any * new global per-adapter data should put in here. - * */ typedef struct adapter { - struct Scsi_Host *sh; /* Pointer to Scsi_Host structure */ - int iobase; /* This adapter's I/O base address */ - int irq; /* This adapter's IRQ level */ - int dma; /* This adapter's DMA channel */ - struct { /* This adapter's mailboxes */ - Mailbox ogmb[OGMB_CNT]; /* Outgoing mailboxes */ - Mailbox icmb[ICMB_CNT]; /* Incoming mailboxes */ - } mb; - int next_ogmb; /* to reduce contention at mailboxes */ - unchar control; /* shadows CONTROL port value */ - unchar rev1, rev2; /* filled in by wd7000_revision */ + struct Scsi_Host *sh; /* Pointer to Scsi_Host structure */ + int iobase; /* This adapter's I/O base address */ + int irq; /* This adapter's IRQ level */ + int dma; /* This adapter's DMA channel */ + int int_counter; /* This adapter's interrupt counter */ + int bus_on; /* This adapter's BUS_ON time */ + int bus_off; /* This adapter's BUS_OFF time */ + struct { /* This adapter's mailboxes */ + Mailbox ogmb[OGMB_CNT]; /* Outgoing mailboxes */ + Mailbox icmb[ICMB_CNT]; /* Incoming mailboxes */ + } mb; + int next_ogmb; /* to reduce contention at mailboxes */ + unchar control; /* shadows CONTROL port value */ + unchar rev1, rev2; /* filled in by wd7000_revision */ } Adapter; /* - * The following is set up by wd7000_detect, and used thereafter by - * wd7000_intr_handle to map the irq level to the corresponding Adapter. - * Note that if SA_INTERRUPT is not used, wd7000_intr_handle must be - * changed to pick up the IRQ level correctly. - */ -static Adapter *irq2host[NR_IRQS] = {NULL}; - -/* * (linear) base address for ROM BIOS */ -static const long wd7000_biosaddr[] = { - 0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000, - 0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000 +static const long wd7000_biosaddr[] = +{ + 0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000, + 0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000 }; #define NUM_ADDRS (sizeof(wd7000_biosaddr)/sizeof(long)) -static const unsigned short wd7000_iobase[] = { - 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338, - 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378, - 0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8, - 0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8 +static const unsigned short wd7000_iobase[] = +{ + 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338, + 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378, + 0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8, + 0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8 }; #define NUM_IOPORTS (sizeof(wd7000_iobase)/sizeof(unsigned short)) @@ -240,24 +254,48 @@ static const short wd7000_dma[] = { 5, 6, 7 }; #define NUM_DMAS (sizeof(wd7000_dma)/sizeof(short)) - + +/* + * possible irq range + */ +#define IRQ_MIN 3 +#define IRQ_MAX 15 +#define IRQS (IRQ_MAX - IRQ_MIN + 1) + +/* + * The following is set up by wd7000_detect, and used thereafter by + * wd7000_intr_handle to map the irq level to the corresponding Adapter. + * Note that if SA_INTERRUPT is not used, wd7000_intr_handle must be + * changed to pick up the IRQ level correctly. + */ +static struct Scsi_Host *wd7000_host[IRQS]; + +#define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */ +#define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */ + /* * Standard Adapter Configurations - used by wd7000_detect */ typedef struct { - int irq; /* IRQ level */ - int dma; /* DMA channel */ - unsigned iobase; /* I/O base address */ + short irq; /* IRQ level */ + short dma; /* DMA channel */ + unsigned iobase; /* I/O base address */ + short bus_on; /* Time that WD7000 spends on the AT-bus when */ + /* transferring data. BIOS default is 8000ns. */ + short bus_off; /* Time that WD7000 spends OFF THE BUS after */ + /* while it is transferring data. */ + /* BIOS default is 1875ns */ } Config; /* * Add here your configuration... */ -static const Config configs[] = { - { 15, 6, 0x350 }, /* defaults for single adapter */ - { 11, 5, 0x320 }, /* defaults for second adapter */ - { 7, 6, 0x350 }, /* My configuration (Zaga) */ - { -1, -1, 0x0 } /* Empty slot */ +static Config configs[] = +{ + { 15, 6, 0x350, BUS_ON, BUS_OFF }, /* defaults for single adapter */ + { 11, 5, 0x320, BUS_ON, BUS_OFF }, /* defaults for second adapter */ + { 7, 6, 0x350, BUS_ON, BUS_OFF }, /* My configuration (Zaga) */ + { -1, -1, 0x0, BUS_ON, BUS_OFF } /* Empty slot */ }; #define NUM_CONFIGS (sizeof(configs)/sizeof(Config)) @@ -267,13 +305,14 @@ * added for the Future Domain version. */ typedef struct signature { - const void *sig; /* String to look for */ - unsigned ofs; /* offset from BIOS base address */ - unsigned len; /* length of string */ + const char *sig; /* String to look for */ + unsigned long ofs; /* offset from BIOS base address */ + unsigned len; /* length of string */ } Signature; -static const Signature signatures[] = { - { "SSTBIOS", 0x0000d, 7 } /* "SSTBIOS" @ offset 0x0000d */ +static const Signature signatures[] = +{ + {"SSTBIOS", 0x0000d, 7} /* "SSTBIOS" @ offset 0x0000d */ }; #define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature)) @@ -282,22 +321,23 @@ * I/O Port Offsets and Bit Definitions * 4 addresses are used. Those not defined here are reserved. */ -#define ASC_STAT 0 /* Status, Read */ -#define ASC_COMMAND 0 /* Command, Write */ +#define ASC_STAT 0 /* Status, Read */ +#define ASC_COMMAND 0 /* Command, Write */ #define ASC_INTR_STAT 1 /* Interrupt Status, Read */ -#define ASC_INTR_ACK 1 /* Acknowledge, Write */ -#define ASC_CONTROL 2 /* Control, Write */ +#define ASC_INTR_ACK 1 /* Acknowledge, Write */ +#define ASC_CONTROL 2 /* Control, Write */ /* * ASC Status Port */ -#define INT_IM 0x80 /* Interrupt Image Flag */ -#define CMD_RDY 0x40 /* Command Port Ready */ -#define CMD_REJ 0x20 /* Command Port Byte Rejected */ -#define ASC_INIT 0x10 /* ASC Initialized Flag */ +#define INT_IM 0x80 /* Interrupt Image Flag */ +#define CMD_RDY 0x40 /* Command Port Ready */ +#define CMD_REJ 0x20 /* Command Port Byte Rejected */ +#define ASC_INIT 0x10 /* ASC Initialized Flag */ #define ASC_STATMASK 0xf0 /* The lower 4 Bytes are reserved */ -/* COMMAND opcodes +/* + * COMMAND opcodes * * Unfortunately, I have no idea how to properly use some of these commands, * as the OEM manual does not make it clear. I have not been able to use @@ -305,39 +345,38 @@ * discernible effect whatsoever. I think they may be related to certain * ICB commands, but again, the OEM manual doesn't make that clear. */ -#define NO_OP 0 /* NO-OP toggles CMD_RDY bit in ASC_STAT */ -#define INITIALIZATION 1 /* initialization (10 bytes) */ -#define DISABLE_UNS_INTR 2 /* disable unsolicited interrupts */ -#define ENABLE_UNS_INTR 3 /* enable unsolicited interrupts */ -#define INTR_ON_FREE_OGMB 4 /* interrupt on free OGMB */ -#define SOFT_RESET 5 /* SCSI bus soft reset */ -#define HARD_RESET_ACK 6 /* SCSI bus hard reset acknowledge */ -#define START_OGMB 0x80 /* start command in OGMB (n) */ +#define NO_OP 0 /* NO-OP toggles CMD_RDY bit in ASC_STAT */ +#define INITIALIZATION 1 /* initialization (10 bytes) */ +#define DISABLE_UNS_INTR 2 /* disable unsolicited interrupts */ +#define ENABLE_UNS_INTR 3 /* enable unsolicited interrupts */ +#define INTR_ON_FREE_OGMB 4 /* interrupt on free OGMB */ +#define SOFT_RESET 5 /* SCSI bus soft reset */ +#define HARD_RESET_ACK 6 /* SCSI bus hard reset acknowledge */ +#define START_OGMB 0x80 /* start command in OGMB (n) */ #define SCAN_OGMBS 0xc0 /* start multiple commands, signature (n) */ - /* where (n) = lower 6 bits */ -/* For INITIALIZATION: + /* where (n) = lower 6 bits */ +/* + * For INITIALIZATION: */ typedef struct initCmd { - unchar op; /* command opcode (= 1) */ - unchar ID; /* Adapter's SCSI ID */ - unchar bus_on; /* Bus on time, x 125ns (see below) */ - unchar bus_off; /* Bus off time, "" "" */ - unchar rsvd; /* Reserved */ - unchar mailboxes[3]; /* Address of Mailboxes, MSB first */ - unchar ogmbs; /* Number of outgoing MBs, max 64, 0,1 = 1 */ - unchar icmbs; /* Number of incoming MBs, "" "" */ + unchar op; /* command opcode (= 1) */ + unchar ID; /* Adapter's SCSI ID */ + unchar bus_on; /* Bus on time, x 125ns (see below) */ + unchar bus_off; /* Bus off time, "" "" */ + unchar rsvd; /* Reserved */ + unchar mailboxes[3]; /* Address of Mailboxes, MSB first */ + unchar ogmbs; /* Number of outgoing MBs, max 64, 0,1 = 1 */ + unchar icmbs; /* Number of incoming MBs, "" "" */ } InitCmd; -#define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */ -#define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */ - -/* Interrupt Status Port - also returns diagnostic codes at ASC reset +/* + * Interrupt Status Port - also returns diagnostic codes at ASC reset * * if msb is zero, the lower bits are diagnostic status * Diagnostics: - * 01 No diagnostic error occurred - * 02 RAM failure - * 03 FIFO R/W failed + * 01 No diagnostic error occurred + * 02 RAM failure + * 03 FIFO R/W failed * 04 SBIC register read/write failed * 05 Initialization D-FF failed * 06 Host IRQ D-FF failed @@ -346,19 +385,20 @@ * 10NNNNNN outgoing mailbox NNNNNN is free * 11NNNNNN incoming mailbox NNNNNN needs service */ -#define MB_INTR 0xC0 /* Mailbox Service possible/required */ -#define IMB_INTR 0x40 /* 1 Incoming / 0 Outgoing */ -#define MB_MASK 0x3f /* mask for mailbox number */ +#define MB_INTR 0xC0 /* Mailbox Service possible/required */ +#define IMB_INTR 0x40 /* 1 Incoming / 0 Outgoing */ +#define MB_MASK 0x3f /* mask for mailbox number */ -/* CONTROL port bits +/* + * CONTROL port bits */ -#define INT_EN 0x08 /* Interrupt Enable */ -#define DMA_EN 0x04 /* DMA Enable */ -#define SCSI_RES 0x02 /* SCSI Reset */ -#define ASC_RES 0x01 /* ASC Reset */ +#define INT_EN 0x08 /* Interrupt Enable */ +#define DMA_EN 0x04 /* DMA Enable */ +#define SCSI_RES 0x02 /* SCSI Reset */ +#define ASC_RES 0x01 /* ASC Reset */ /* - * Driver data structures: + * Driver data structures: * - mb and scbs are required for interfacing with the host adapter. * An SCB has extra fields not visible to the adapter; mb's * _cannot_ do this, since the adapter assumes they are contiguous in @@ -387,28 +427,28 @@ */ typedef struct sgb { unchar len[3]; - unchar ptr[3]; /* Also SCSI-style - MSB first */ + unchar ptr[3]; /* Also SCSI-style - MSB first */ } Sgb; -typedef struct scb { /* Command Control Block 5.4.1 */ - unchar op; /* Command Control Block Operation Code */ - unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */ - /* Outbound data transfer, length is checked*/ - /* Inbound data transfer, length is checked */ - /* Logical Unit Number */ - unchar cdb[12]; /* SCSI Command Block */ - volatile unchar status; /* SCSI Return Status */ - volatile unchar vue; /* Vendor Unique Error Code */ - unchar maxlen[3]; /* Maximum Data Transfer Length */ - unchar dataptr[3]; /* SCSI Data Block Pointer */ - unchar linkptr[3]; /* Next Command Link Pointer */ - unchar direc; /* Transfer Direction */ - unchar reserved2[6]; /* SCSI Command Descriptor Block */ - /* end of hardware SCB */ - Scsi_Cmnd *SCpnt; /* Scsi_Cmnd using this SCB */ - Sgb sgb[WD7000_SG]; /* Scatter/gather list for this SCB */ - Adapter *host; /* host adapter */ - struct scb *next; /* for lists of scbs */ +typedef struct scb { /* Command Control Block 5.4.1 */ + unchar op; /* Command Control Block Operation Code */ + unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */ + /* Outbound data transfer, length is checked */ + /* Inbound data transfer, length is checked */ + /* Logical Unit Number */ + unchar cdb[12]; /* SCSI Command Block */ + volatile unchar status; /* SCSI Return Status */ + volatile unchar vue; /* Vendor Unique Error Code */ + unchar maxlen[3]; /* Maximum Data Transfer Length */ + unchar dataptr[3]; /* SCSI Data Block Pointer */ + unchar linkptr[3]; /* Next Command Link Pointer */ + unchar direc; /* Transfer Direction */ + unchar reserved2[6]; /* SCSI Command Descriptor Block */ + /* end of hardware SCB */ + Scsi_Cmnd *SCpnt; /* Scsi_Cmnd using this SCB */ + Sgb sgb[WD7000_SG]; /* Scatter/gather list for this SCB */ + Adapter *host; /* host adapter */ + struct scb *next; /* for lists of scbs */ } Scb; /* @@ -422,110 +462,110 @@ * (notably, get/set unsolicited interrupt status) in my copy of the OEM * manual, and others are ambiguous/hard to follow. */ -#define ICB_OP_MASK 0x80 /* distinguishes scbs from icbs */ -#define ICB_OP_OPEN_RBUF 0x80 /* open receive buffer */ -#define ICB_OP_RECV_CMD 0x81 /* receive command from initiator */ -#define ICB_OP_RECV_DATA 0x82 /* receive data from initiator */ -#define ICB_OP_RECV_SDATA 0x83 /* receive data with status from init. */ -#define ICB_OP_SEND_DATA 0x84 /* send data with status to initiator */ -#define ICB_OP_SEND_STAT 0x86 /* send command status to initiator */ - /* 0x87 is reserved */ -#define ICB_OP_READ_INIT 0x88 /* read initialization bytes */ -#define ICB_OP_READ_ID 0x89 /* read adapter's SCSI ID */ -#define ICB_OP_SET_UMASK 0x8A /* set unsolicited interrupt mask */ -#define ICB_OP_GET_UMASK 0x8B /* read unsolicited interrupt mask */ -#define ICB_OP_GET_REVISION 0x8C /* read firmware revision level */ -#define ICB_OP_DIAGNOSTICS 0x8D /* execute diagnostics */ -#define ICB_OP_SET_EPARMS 0x8E /* set execution parameters */ -#define ICB_OP_GET_EPARMS 0x8F /* read execution parameters */ +#define ICB_OP_MASK 0x80 /* distinguishes scbs from icbs */ +#define ICB_OP_OPEN_RBUF 0x80 /* open receive buffer */ +#define ICB_OP_RECV_CMD 0x81 /* receive command from initiator */ +#define ICB_OP_RECV_DATA 0x82 /* receive data from initiator */ +#define ICB_OP_RECV_SDATA 0x83 /* receive data with status from init. */ +#define ICB_OP_SEND_DATA 0x84 /* send data with status to initiator */ +#define ICB_OP_SEND_STAT 0x86 /* send command status to initiator */ + /* 0x87 is reserved */ +#define ICB_OP_READ_INIT 0x88 /* read initialization bytes */ +#define ICB_OP_READ_ID 0x89 /* read adapter's SCSI ID */ +#define ICB_OP_SET_UMASK 0x8A /* set unsolicited interrupt mask */ +#define ICB_OP_GET_UMASK 0x8B /* read unsolicited interrupt mask */ +#define ICB_OP_GET_REVISION 0x8C /* read firmware revision level */ +#define ICB_OP_DIAGNOSTICS 0x8D /* execute diagnostics */ +#define ICB_OP_SET_EPARMS 0x8E /* set execution parameters */ +#define ICB_OP_GET_EPARMS 0x8F /* read execution parameters */ typedef struct icbRecvCmd { - unchar op; - unchar IDlun; /* Initiator SCSI ID/lun */ - unchar len[3]; /* command buffer length */ - unchar ptr[3]; /* command buffer address */ - unchar rsvd[7]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ + unchar op; + unchar IDlun; /* Initiator SCSI ID/lun */ + unchar len[3]; /* command buffer length */ + unchar ptr[3]; /* command buffer address */ + unchar rsvd[7]; /* reserved */ + volatile unchar vue; /* vendor-unique error code */ + volatile unchar status; /* returned (icmb) status */ + volatile unchar phase; /* used by interrupt handler */ } IcbRecvCmd; typedef struct icbSendStat { - unchar op; - unchar IDlun; /* Target SCSI ID/lun */ - unchar stat; /* (outgoing) completion status byte 1 */ - unchar rsvd[12]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ + unchar op; + unchar IDlun; /* Target SCSI ID/lun */ + unchar stat; /* (outgoing) completion status byte 1 */ + unchar rsvd[12]; /* reserved */ + volatile unchar vue; /* vendor-unique error code */ + volatile unchar status; /* returned (icmb) status */ + volatile unchar phase; /* used by interrupt handler */ } IcbSendStat; typedef struct icbRevLvl { - unchar op; - volatile unchar primary; /* primary revision level (returned) */ - volatile unchar secondary; /* secondary revision level (returned) */ - unchar rsvd[12]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ + unchar op; + volatile unchar primary; /* primary revision level (returned) */ + volatile unchar secondary; /* secondary revision level (returned) */ + unchar rsvd[12]; /* reserved */ + volatile unchar vue; /* vendor-unique error code */ + volatile unchar status; /* returned (icmb) status */ + volatile unchar phase; /* used by interrupt handler */ } IcbRevLvl; -typedef struct icbUnsMask { /* I'm totally guessing here */ - unchar op; - volatile unchar mask[14]; /* mask bits */ -#if 0 - unchar rsvd[12]; /* reserved */ -#endif - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ +typedef struct icbUnsMask { /* I'm totally guessing here */ + unchar op; + volatile unchar mask[14]; /* mask bits */ +#ifdef 0 + unchar rsvd[12]; /* reserved */ +#endif + volatile unchar vue; /* vendor-unique error code */ + volatile unchar status; /* returned (icmb) status */ + volatile unchar phase; /* used by interrupt handler */ } IcbUnsMask; typedef struct icbDiag { - unchar op; - unchar type; /* diagnostics type code (0-3) */ - unchar len[3]; /* buffer length */ - unchar ptr[3]; /* buffer address */ - unchar rsvd[7]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ + unchar op; + unchar type; /* diagnostics type code (0-3) */ + unchar len[3]; /* buffer length */ + unchar ptr[3]; /* buffer address */ + unchar rsvd[7]; /* reserved */ + volatile unchar vue; /* vendor-unique error code */ + volatile unchar status; /* returned (icmb) status */ + volatile unchar phase; /* used by interrupt handler */ } IcbDiag; -#define ICB_DIAG_POWERUP 0 /* Power-up diags only */ -#define ICB_DIAG_WALKING 1 /* walking 1's pattern */ -#define ICB_DIAG_DMA 2 /* DMA - system memory diags */ -#define ICB_DIAG_FULL 3 /* do both 1 & 2 */ +#define ICB_DIAG_POWERUP 0 /* Power-up diags only */ +#define ICB_DIAG_WALKING 1 /* walking 1's pattern */ +#define ICB_DIAG_DMA 2 /* DMA - system memory diags */ +#define ICB_DIAG_FULL 3 /* do both 1 & 2 */ typedef struct icbParms { - unchar op; - unchar rsvd1; /* reserved */ - unchar len[3]; /* parms buffer length */ - unchar ptr[3]; /* parms buffer address */ - unchar idx[2]; /* index (MSB-LSB) */ - unchar rsvd2[5]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ + unchar op; + unchar rsvd1; /* reserved */ + unchar len[3]; /* parms buffer length */ + unchar ptr[3]; /* parms buffer address */ + unchar idx[2]; /* index (MSB-LSB) */ + unchar rsvd2[5]; /* reserved */ + volatile unchar vue; /* vendor-unique error code */ + volatile unchar status; /* returned (icmb) status */ + volatile unchar phase; /* used by interrupt handler */ } IcbParms; typedef struct icbAny { - unchar op; - unchar data[14]; /* format-specific data */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ + unchar op; + unchar data[14]; /* format-specific data */ + volatile unchar vue; /* vendor-unique error code */ + volatile unchar status; /* returned (icmb) status */ + volatile unchar phase; /* used by interrupt handler */ } IcbAny; typedef union icb { - unchar op; /* ICB opcode */ - IcbRecvCmd recv_cmd; /* format for receive command */ - IcbSendStat send_stat; /* format for send status */ - IcbRevLvl rev_lvl; /* format for get revision level */ - IcbDiag diag; /* format for execute diagnostics */ - IcbParms eparms; /* format for get/set exec parms */ - IcbAny icb; /* generic format */ - unchar data[18]; + unchar op; /* ICB opcode */ + IcbRecvCmd recv_cmd; /* format for receive command */ + IcbSendStat send_stat; /* format for send status */ + IcbRevLvl rev_lvl; /* format for get revision level */ + IcbDiag diag; /* format for execute diagnostics */ + IcbParms eparms; /* format for get/set exec parms */ + IcbAny icb; /* generic format */ + unchar data[18]; } Icb; @@ -536,27 +576,34 @@ * structure is not part of the Adapter structure. */ static Scb scbs[MAX_SCBS]; -static Scb *scbfree = NULL; /* free list */ -static int freescbs = MAX_SCBS; /* free list counter */ - -/* - * - */ -static short wd7000_setupIRQ[NUM_CONFIGS]; -static short wd7000_setupDMA[NUM_CONFIGS]; -static short wd7000_setupIO[NUM_CONFIGS]; -static short wd7000_card_num = 0; +static Scb *scbfree = NULL; /* free list */ +static int freescbs = MAX_SCBS; /* free list counter */ /* * END of data/declarations - code follows. */ +static void setup_error (char *mesg, int *ints) +{ + if (ints[0] == 3) + printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n", + ints[1], ints[2], ints[3], mesg); + else if (ints[0] == 4) + printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n", + ints[1], ints[2], ints[3], ints[4], mesg); + else + printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n", + ints[1], ints[2], ints[3], ints[4], ints[5], mesg); +} /* * Note: You can now set these options from the kernel's "command line". * The syntax is: * - * wd7000=IRQ,DMA,IO + * wd7000=,,[,[,]] + * + * , where BUS_ON and BUS_OFF are in nanoseconds. BIOS default values + * are 8000ns for BUS_ON and 1875ns for BUS_OFF. * eg: * wd7000=7,6,0x350 * @@ -565,82 +612,99 @@ */ void wd7000_setup (char *str, int *ints) { + static short wd7000_card_num = 0; short i, j; if (wd7000_card_num >= NUM_CONFIGS) { - printk ("wd7000_setup: Too many \"wd7000=\" configurations in " - "command line!\n"); - - return; + printk ("wd7000_setup: Too many \"wd7000=\" configurations in " + "command line!\n"); + return; } - if (ints[0] != 3) + if ((ints[0] < 3) || (ints[0] > 5)) printk ("wd7000_setup: Error in command line! " - "Usage: wd7000=IRQ,DMA,IO\n"); + "Usage: wd7000=,,IO>[,[,]]\n"); else { for (i = 0; i < NUM_IRQS; i++) if (ints[1] == wd7000_irq[i]) break; if (i == NUM_IRQS) { - printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> " - "invalid IRQ.\n", ints[1], ints[2], ints[3]); + setup_error ("invalid IRQ.", ints); return; } else - wd7000_setupIRQ[wd7000_card_num] = ints[1]; + configs[wd7000_card_num].irq = ints[1]; for (i = 0; i < NUM_DMAS; i++) if (ints[2] == wd7000_dma[i]) break; if (i == NUM_DMAS) { - printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> " - "invalid DMA channel.\n", ints[1], ints[2], ints[3]); + setup_error ("invalid DMA channel.", ints); return; } else - wd7000_setupDMA[wd7000_card_num] = ints[2]; + configs[wd7000_card_num].dma = ints[2]; for (i = 0; i < NUM_IOPORTS; i++) if (ints[3] == wd7000_iobase[i]) break; if (i == NUM_IOPORTS) { - printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> " - "invalid I/O base address.\n", ints[1], ints[2], ints[3]); + setup_error ("invalid I/O base address.", ints); return; } else - wd7000_setupIO[wd7000_card_num] = ints[3]; + configs[wd7000_card_num].iobase = ints[3]; + + if (ints[0] > 3) { + if ((ints[4] < 500) || (ints[4] > 31875)) { + setup_error ("BUS_ON value is out of range (500 to 31875 nanoseconds)!", + ints); + configs[wd7000_card_num].bus_on = BUS_ON; + } + else + configs[wd7000_card_num].bus_on = ints[4] / 125.0; + } + else + configs[wd7000_card_num].bus_on = BUS_ON; + + if (ints[0] > 4) { + if ((ints[5] < 500) || (ints[5] > 31875)) { + setup_error ("BUS_OFF value is out of range (500 to 31875 nanoseconds)!", + ints); + configs[wd7000_card_num].bus_off = BUS_OFF; + } + else + configs[wd7000_card_num].bus_off = ints[5] / 125.0; + } + else + configs[wd7000_card_num].bus_off = BUS_OFF; if (wd7000_card_num) for (i = 0; i < (wd7000_card_num - 1); i++) - for (j = i + 1; j < wd7000_card_num; j++) - if (wd7000_setupIRQ[i] == wd7000_setupIRQ[j]) { - printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> " - "duplicated IRQ!\n", - ints[1], ints[2], ints[3]); - return; - } - else if (wd7000_setupDMA[i] == wd7000_setupDMA[j]) { - printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> " - "duplicated DMA channel!\n", - ints[1], ints[2], ints[3]); - return; - } - else if (wd7000_setupIO[i] == wd7000_setupIO[j]) { - printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> " - "duplicated I/O base address!\n", - ints[1], ints[2], ints[3]); - return; - } - -#ifdef DEBUG - printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x\n", - wd7000_setupIRQ[wd7000_card_num], - wd7000_setupDMA[wd7000_card_num], - wd7000_setupIO[wd7000_card_num]); + for (j = i + 1; j < wd7000_card_num; j++) + if (configs[i].irq == configs[j].irq) { + setup_error ("duplicated IRQ!", ints); + return; + } + else if (configs[i].dma == configs[j].dma) { + setup_error ("duplicated DMA channel!", ints); + return; + } + else if (configs[i].iobase == configs[j].iobase) { + setup_error ("duplicated I/O base address!", ints); + return; + } + +#ifdef WD7000_DEBUG + printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n", + configs[wd7000_card_num].irq, + configs[wd7000_card_num].dma, + configs[wd7000_card_num].iobase, + configs[wd7000_card_num].bus_on * 125, + configs[wd7000_card_num].bus_off * 125); #endif wd7000_card_num++; @@ -650,21 +714,20 @@ #ifdef ANY2SCSI_INLINE /* - Since they're used a lot, I've redone the following from the macros - formerly in wd7000.h, hopefully to speed them up by getting rid of - all the shifting (it may not matter; GCC might have done as well anyway). - - xany2scsi and xscsi2int were not being used, and are no longer defined. - (They were simply 4-byte versions of these routines). -*/ - -typedef union { /* let's cheat... */ - int i; - unchar u[sizeof(int)]; /* the sizeof(int) makes it more portable */ + * Since they're used a lot, I've redone the following from the macros + * formerly in wd7000.h, hopefully to speed them up by getting rid of + * all the shifting (it may not matter; GCC might have done as well anyway). + * + * xany2scsi and xscsi2int were not being used, and are no longer defined. + * (They were simply 4-byte versions of these routines). + */ +typedef union { /* let's cheat... */ + int i; + unchar u[sizeof (int)]; /* the sizeof(int) makes it more portable */ } i_u; -static inline void any2scsi( unchar *scsi, int any ) +static inline void any2scsi (unchar * scsi, int any) { *scsi++ = ((i_u) any).u[2]; *scsi++ = ((i_u) any).u[1]; @@ -672,49 +735,50 @@ } -static inline int scsi2int( unchar *scsi ) +static inline int scsi2int (unchar * scsi) { i_u result; - result.i = 0; /* clears unused bytes */ - *(result.u+2) = *scsi++; - *(result.u+1) = *scsi++; - *(result.u) = *scsi++; - return result.i; + result.i = 0; /* clears unused bytes */ + result.u[2] = *scsi++; + result.u[1] = *scsi++; + result.u[0] = *scsi++; + + return (result.i); } #else /* - These are the old ones - I've just moved them here... -*/ + * These are the old ones - I've just moved them here... + */ #undef any2scsi -#define any2scsi(up, p) \ -(up)[0] = (((unsigned long)(p)) >> 16); \ -(up)[1] = ((unsigned long)(p)) >> 8; \ -(up)[2] = ((unsigned long)(p)); +#define any2scsi(up, p) (up)[0] = (((unsigned long) (p)) >> 16); \ + (up)[1] = ((unsigned long) (p)) >> 8; \ + (up)[2] = ((unsigned long) (p)); #undef scsi2int -#define scsi2int(up) ( (((unsigned long)*(up)) << 16) + \ - (((unsigned long)(up)[1]) << 8) + ((unsigned long)(up)[2]) ) +#define scsi2int(up) ( (((unsigned long) *(up)) << 16) + \ + (((unsigned long) (up)[1]) << 8) + \ + ((unsigned long) (up)[2]) ) #endif - -static inline void wd7000_enable_intr(Adapter *host) + +static inline void wd7000_enable_intr (Adapter *host) { host->control |= INT_EN; - outb(host->control, host->iobase+ASC_CONTROL); + outb (host->control, host->iobase + ASC_CONTROL); } -static inline void wd7000_enable_dma(Adapter *host) +static inline void wd7000_enable_dma (Adapter *host) { host->control |= DMA_EN; - outb(host->control,host->iobase+ASC_CONTROL); - set_dma_mode(host->dma, DMA_MODE_CASCADE); - enable_dma(host->dma); + outb (host->control, host->iobase + ASC_CONTROL); + set_dma_mode (host->dma, DMA_MODE_CASCADE); + enable_dma (host->dma); } -#define WAITnexttimeout 200 /* 2 seconds */ +#define WAITnexttimeout 200 /* 2 seconds */ static inline short WAIT (unsigned port, unsigned mask, unsigned allof, unsigned noneof) { @@ -722,7 +786,7 @@ register unsigned long WAITtimeout = jiffies + WAITnexttimeout; while (jiffies <= WAITtimeout) { - WAITbits = inb (port) & mask; + WAITbits = inb (port) & mask; if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0)) return (0); @@ -732,31 +796,32 @@ } -static inline void delay( unsigned how_long ) +static inline void delay (unsigned how_long) { - register unsigned long time = jiffies + how_long; + register unsigned long time = jiffies + how_long; - while (jiffies < time); + while (jiffies < time); } -static inline int command_out(Adapter *host, unchar *cmd, int len) +static inline int command_out (Adapter * host, unchar * cmd, int len) { - if (! WAIT (host->iobase+ASC_STAT,ASC_STATMASK,CMD_RDY,0)) { - while (len--) { - do { - outb(*cmd, host->iobase+ASC_COMMAND); - WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0); - } while (inb(host->iobase+ASC_STAT) & CMD_REJ); + if (!WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { + while (len--) { + do { + outb (*cmd, host->iobase + ASC_COMMAND); + WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0); + } while (inb (host->iobase + ASC_STAT) & CMD_REJ); cmd++; } - return 1; + return (1); } - printk("wd7000 command_out: WAIT failed(%d)\n", len+1); - return 0; + printk ("wd7000 command_out: WAIT failed(%d)\n", len + 1); + + return (0); } @@ -770,7 +835,7 @@ * the satisfiability of a request is not dependent on the size of the * request. */ -static inline Scb *alloc_scbs(int needed) +static inline Scb *alloc_scbs (int needed) { register Scb *scb, *p; register unsigned long flags; @@ -779,84 +844,89 @@ static int busy = 0; int i; - if (needed <= 0) return NULL; /* sanity check */ + if (needed <= 0) + return (NULL); /* sanity check */ - save_flags(flags); - cli(); - while (busy) { /* someone else is allocating */ - sti(); /* Yes this is really needed here */ - now = jiffies; while (jiffies == now) /* wait a jiffy */; - cli(); + save_flags (flags); + cli (); + while (busy) { /* someone else is allocating */ + sti (); /* Yes this is really needed here */ + for (now = jiffies; now == jiffies; ); /* wait a jiffy */ + cli (); } - busy = 1; /* not busy now; it's our turn */ + busy = 1; /* not busy now; it's our turn */ - while (freescbs < needed) { + while (freescbs < needed) { timeout = jiffies + WAITnexttimeout; do { - sti(); /* Yes this is really needed here */ - now = jiffies; - while (jiffies == now); /* wait a jiffy */ - cli(); - } while (freescbs < needed && jiffies <= timeout); + sti (); /* Yes this is really needed here */ + for (now = jiffies; now == jiffies; ); /* wait a jiffy */ + cli (); + } while (freescbs < needed && jiffies <= timeout); /* * If we get here with enough free Scbs, we can take them. * Otherwise, we timed out and didn't get enough. */ - if (freescbs < needed) { + if (freescbs < needed) { busy = 0; - panic("wd7000: can't get enough free SCBs.\n"); - restore_flags(flags); - return NULL; + panic ("wd7000: can't get enough free SCBs.\n"); + restore_flags (flags); + return (NULL); } } - scb = scbfree; freescbs -= needed; - for (i = 0; i < needed; i++) { p = scbfree; scbfree = p->next; } + scb = scbfree; + freescbs -= needed; + for (i = 0; i < needed; i++) { + p = scbfree; + scbfree = p->next; + } p->next = NULL; - - busy = 0; /* we're done */ + busy = 0; /* we're done */ - restore_flags(flags); + restore_flags (flags); - return scb; + return (scb); } -static inline void free_scb( Scb *scb ) +static inline void free_scb (Scb *scb) { register unsigned long flags; - save_flags(flags); - cli(); + save_flags (flags); + cli (); - memset(scb, 0, sizeof(Scb)); - scb->next = scbfree; scbfree = scb; + memset (scb, 0, sizeof (Scb)); + scb->next = scbfree; + scbfree = scb; freescbs++; - restore_flags(flags); + restore_flags (flags); } -static inline void init_scbs(void) +static inline void init_scbs (void) { int i; unsigned long flags; - save_flags(flags); - cli(); + save_flags (flags); + cli (); scbfree = &(scbs[0]); - memset(scbs, 0, sizeof(scbs)); - for (i = 0; i < MAX_SCBS-1; i++) { - scbs[i].next = &(scbs[i+1]); scbs[i].SCpnt = NULL; - } - scbs[MAX_SCBS-1].next = NULL; - scbs[MAX_SCBS-1].SCpnt = NULL; - - restore_flags(flags); -} - + memset (scbs, 0, sizeof (scbs)); + for (i = 0; i < MAX_SCBS - 1; i++) { + scbs[i].next = &(scbs[i + 1]); + scbs[i].SCpnt = NULL; + } + scbs[MAX_SCBS - 1].next = NULL; + scbs[MAX_SCBS - 1].SCpnt = NULL; + + restore_flags (flags); +} -static int mail_out( Adapter *host, Scb *scbptr ) + +static int mail_out (Adapter *host, Scb *scbptr) /* * Note: this can also be used for ICBs; just cast to the parm type. */ @@ -866,30 +936,35 @@ unchar start_ogmb; Mailbox *ogmbs = host->mb.ogmb; int *next_ogmb = &(host->next_ogmb); -#ifdef DEBUG - printk("wd7000 mail_out: 0x%06lx",(long) scbptr); + +#ifdef WD7000_DEBUG + printk ("wd7000_mail_out: 0x%06lx", (long) scbptr); #endif + /* We first look for a free outgoing mailbox */ - save_flags(flags); - cli(); + save_flags (flags); + cli (); ogmb = *next_ogmb; for (i = 0; i < OGMB_CNT; i++) { - if (ogmbs[ogmb].status == 0) { -#ifdef DEBUG - printk(" using OGMB 0x%x",ogmb); + if (ogmbs[ogmb].status == 0) { +#ifdef WD7000_DEBUG + printk (" using OGMB 0x%x", ogmb); #endif ogmbs[ogmb].status = 1; - any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr); + any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr); - *next_ogmb = (ogmb+1) % OGMB_CNT; + *next_ogmb = (ogmb + 1) % OGMB_CNT; break; - } else + } + else ogmb = (++ogmb) % OGMB_CNT; } - restore_flags(flags); -#ifdef DEBUG - printk(", scb is 0x%06lx",(long) scbptr); + restore_flags (flags); + +#ifdef WD7000_DEBUG + printk (", scb is 0x%06lx", (long) scbptr); #endif + if (i >= OGMB_CNT) { /* * Alternatively, we might issue the "interrupt on free OGMB", @@ -899,171 +974,182 @@ * that marks OGMB's free, waiting even with interrupts off * should work, since they are freed very quickly in most cases. */ - #ifdef DEBUG - printk(", no free OGMBs.\n"); +#ifdef WD7000_DEBUG + printk (", no free OGMBs.\n"); #endif - return 0; + return (0); } - wd7000_enable_intr(host); + wd7000_enable_intr (host); start_ogmb = START_OGMB | ogmb; - command_out( host, &start_ogmb, 1 ); -#ifdef DEBUG - printk(", awaiting interrupt.\n"); + command_out (host, &start_ogmb, 1); + +#ifdef WD7000_DEBUG + printk (", awaiting interrupt.\n"); #endif - return 1; + + return (1); } -int make_code(unsigned hosterr, unsigned scsierr) -{ -#ifdef DEBUG +int make_code (unsigned hosterr, unsigned scsierr) +{ +#ifdef WD7000_DEBUG int in_error = hosterr; #endif - switch ((hosterr>>8)&0xff){ - case 0: /* Reserved */ - hosterr = DID_ERROR; - break; - case 1: /* Command Complete, no errors */ - hosterr = DID_OK; - break; - case 2: /* Command complete, error logged in scb status (scsierr) */ - hosterr = DID_OK; - break; - case 4: /* Command failed to complete - timeout */ - hosterr = DID_TIME_OUT; - break; - case 5: /* Command terminated; Bus reset by external device */ - hosterr = DID_RESET; - break; - case 6: /* Unexpected Command Received w/ host as target */ - hosterr = DID_BAD_TARGET; - break; + switch ((hosterr >> 8) & 0xff) { + case 0: /* Reserved */ + hosterr = DID_ERROR; + break; + case 1: /* Command Complete, no errors */ + hosterr = DID_OK; + break; + case 2: /* Command complete, error logged in scb status (scsierr) */ + hosterr = DID_OK; + break; + case 4: /* Command failed to complete - timeout */ + hosterr = DID_TIME_OUT; + break; + case 5: /* Command terminated; Bus reset by external device */ + hosterr = DID_RESET; + break; + case 6: /* Unexpected Command Received w/ host as target */ + hosterr = DID_BAD_TARGET; + break; case 80: /* Unexpected Reselection */ case 81: /* Unexpected Selection */ - hosterr = DID_BAD_INTR; - break; + hosterr = DID_BAD_INTR; + break; case 82: /* Abort Command Message */ - hosterr = DID_ABORT; - break; + hosterr = DID_ABORT; + break; case 83: /* SCSI Bus Software Reset */ case 84: /* SCSI Bus Hardware Reset */ - hosterr = DID_RESET; - break; + hosterr = DID_RESET; + break; default: /* Reserved */ - hosterr = DID_ERROR; - break; - } -#ifdef DEBUG - if (scsierr||hosterr) - printk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", - scsierr,in_error,hosterr); + hosterr = DID_ERROR; + } +#ifdef WD7000_DEBUG + if (scsierr || hosterr) + printk ("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", + scsierr, in_error, hosterr); #endif - return scsierr | (hosterr << 16); + return (scsierr | (hosterr << 16)); } -static void wd7000_scsi_done(Scsi_Cmnd * SCpnt) +static void wd7000_scsi_done (Scsi_Cmnd *SCpnt) { -#ifdef DEBUG +#ifdef WD7000_DEBUG printk ("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt); #endif + SCpnt->SCp.phase = 0; } -#define wd7000_intr_ack(host) outb(0,host->iobase+ASC_INTR_ACK) +#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK) -void wd7000_intr_handle(int irq, void *dev_id, struct pt_regs * regs) +void wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs) { register int flag, icmb, errstatus, icmb_status; register int host_error, scsi_error; - register Scb *scb; /* for SCSI commands */ - register IcbAny *icb; /* for host commands */ + register Scb *scb; /* for SCSI commands */ + register IcbAny *icb; /* for host commands */ register Scsi_Cmnd *SCpnt; - Adapter *host = irq2host[irq]; /* This MUST be set!!! */ + Adapter *host = (Adapter *) wd7000_host[irq - IRQ_MIN]->hostdata; /* This MUST be set!!! */ Mailbox *icmbs = host->mb.icmb; -#ifdef DEBUG - printk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host); + host->int_counter++; + +#ifdef WD7000_DEBUG + printk ("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host); #endif - flag = inb(host->iobase+ASC_INTR_STAT); -#ifdef DEBUG - printk("wd7000_intr_handle: intr stat = 0x%02x\n",flag); + flag = inb (host->iobase + ASC_INTR_STAT); + +#ifdef WD7000_DEBUG + printk ("wd7000_intr_handle: intr stat = 0x%02x\n", flag); #endif - if (!(inb(host->iobase+ASC_STAT) & INT_IM)) { + if (!(inb (host->iobase + ASC_STAT) & INT_IM)) { /* NB: these are _very_ possible if IRQ 15 is being used, since - it's the "garbage collector" on the 2nd 8259 PIC. Specifically, - any interrupt signal into the 8259 which can't be identified - comes out as 7 from the 8259, which is 15 to the host. Thus, it - is a good thing the WD7000 has an interrupt status port, so we - can sort these out. Otherwise, electrical noise and other such - problems would be indistinguishable from valid interrupts... - */ -#ifdef DEBUG - printk("wd7000_intr_handle: phantom interrupt...\n"); + * it's the "garbage collector" on the 2nd 8259 PIC. Specifically, + * any interrupt signal into the 8259 which can't be identified + * comes out as 7 from the 8259, which is 15 to the host. Thus, it + * is a good thing the WD7000 has an interrupt status port, so we + * can sort these out. Otherwise, electrical noise and other such + * problems would be indistinguishable from valid interrupts... + */ +#ifdef WD7000_DEBUG + printk ("wd7000_intr_handle: phantom interrupt...\n"); #endif - wd7000_intr_ack(host); - return; + wd7000_intr_ack (host); + return; } - if (flag & MB_INTR) { + if (flag & MB_INTR) { /* The interrupt is for a mailbox */ if (!(flag & IMB_INTR)) { -#ifdef DEBUG - printk("wd7000_intr_handle: free outgoing mailbox\n"); +#ifdef WD7000_DEBUG + printk ("wd7000_intr_handle: free outgoing mailbox\n"); #endif /* * If sleep_on() and the "interrupt on free OGMB" command are * used in mail_out(), wake_up() should correspondingly be called * here. For now, we don't need to do anything special. */ - wd7000_intr_ack(host); + wd7000_intr_ack (host); return; - } else { + } + else { /* The interrupt is for an incoming mailbox */ icmb = flag & MB_MASK; icmb_status = icmbs[icmb].status; - if (icmb_status & 0x80) { /* unsolicited - result in ICMB */ -#ifdef DEBUG - printk("wd7000_intr_handle: unsolicited interrupt 0x%02xh\n", - icmb_status); + if (icmb_status & 0x80) { /* unsolicited - result in ICMB */ +#ifdef WD7000_DEBUG + printk ("wd7000_intr_handle: unsolicited interrupt 0x%02x\n", + icmb_status); #endif - wd7000_intr_ack(host); + wd7000_intr_ack (host); return; } - scb = (struct scb *) scsi2int((unchar *)icmbs[icmb].scbptr); + /* Aaaargh! (Zaga) */ + scb = (struct scb *) (scsi2int ((unchar *) icmbs[icmb].scbptr) | PAGE_OFFSET); icmbs[icmb].status = 0; - if (!(scb->op & ICB_OP_MASK)) { /* an SCB is done */ + if (!(scb->op & ICB_OP_MASK)) { /* an SCB is done */ SCpnt = scb->SCpnt; - if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */ + if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */ host_error = scb->vue | (icmb_status << 8); scsi_error = scb->status; - errstatus = make_code(host_error,scsi_error); + errstatus = make_code (host_error, scsi_error); SCpnt->result = errstatus; - free_scb(scb); + free_scb (scb); - SCpnt->scsi_done(SCpnt); + SCpnt->scsi_done (SCpnt); } - } else { /* an ICB is done */ + } + else { /* an ICB is done */ icb = (IcbAny *) scb; icb->status = icmb_status; - icb->phase = 0; + icb->phase = 0; } - } /* incoming mailbox */ + } /* incoming mailbox */ } - wd7000_intr_ack(host); - return; + wd7000_intr_ack (host); + +#ifdef WD7000_DEBUG + printk ("wd7000_intr_handle: return from interrupt handler\n"); +#endif } -int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +int wd7000_queuecommand (Scsi_Cmnd *SCpnt, void (*done) (Scsi_Cmnd *)) { register Scb *scb; register Sgb *sgb; @@ -1076,94 +1162,105 @@ idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7); SCpnt->scsi_done = done; SCpnt->SCp.phase = 1; - scb = alloc_scbs(1); + scb = alloc_scbs (1); scb->idlun = idlun; - memcpy(scb->cdb, cdb, cdblen); + memcpy (scb->cdb, cdb, cdblen); scb->direc = 0x40; /* Disable direction check */ - scb->SCpnt = SCpnt; /* so we can find stuff later */ + scb->SCpnt = SCpnt; /* so we can find stuff later */ SCpnt->host_scribble = (unchar *) scb; scb->host = host; - if (SCpnt->use_sg) { + if (SCpnt->use_sg) { struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; unsigned i; - if (SCpnt->host->sg_tablesize == SG_NONE) { - panic("wd7000_queuecommand: scatter/gather not supported.\n"); + if (SCpnt->host->sg_tablesize == SG_NONE) { + panic ("wd7000_queuecommand: scatter/gather not supported.\n"); } -#ifdef DEBUG - printk("Using scatter/gather with %d elements.\n",SCpnt->use_sg); +#ifdef WD7000_DEBUG + printk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg); #endif sgb = scb->sgb; - scb->op = 1; - any2scsi(scb->dataptr, (int) sgb); - any2scsi(scb->maxlen, SCpnt->use_sg * sizeof (Sgb) ); - - for (i = 0; i < SCpnt->use_sg; i++) { - any2scsi(sgb[i].ptr, (int) sg[i].address); - any2scsi(sgb[i].len, sg[i].length); + scb->op = 1; + any2scsi (scb->dataptr, (int) sgb); + any2scsi (scb->maxlen, SCpnt->use_sg * sizeof (Sgb)); + + for (i = 0; i < SCpnt->use_sg; i++) { + any2scsi (sgb[i].ptr, (int) sg[i].address); + any2scsi (sgb[i].len, sg[i].length); } - } else { + } + else { scb->op = 0; - any2scsi(scb->dataptr, (int) SCpnt->request_buffer); - any2scsi(scb->maxlen, SCpnt->request_bufflen); + any2scsi (scb->dataptr, (int) SCpnt->request_buffer); + any2scsi (scb->maxlen, SCpnt->request_bufflen); } - while (!mail_out(host, scb)) /* keep trying */; - return 1; + while (!mail_out (host, scb)); /* keep trying */ + + return (1); } -int wd7000_command(Scsi_Cmnd *SCpnt) +int wd7000_command (Scsi_Cmnd *SCpnt) { - wd7000_queuecommand(SCpnt, wd7000_scsi_done); + wd7000_queuecommand (SCpnt, wd7000_scsi_done); - while (SCpnt->SCp.phase > 0) barrier(); /* phase counts scbs down to 0 */ + while (SCpnt->SCp.phase > 0) + barrier (); /* phase counts scbs down to 0 */ - return SCpnt->result; + return (SCpnt->result); } -int wd7000_diagnostics( Adapter *host, int code ) +int wd7000_diagnostics (Adapter *host, int code) { static IcbDiag icb = {ICB_OP_DIAGNOSTICS}; static unchar buf[256]; unsigned long timeout; icb.type = code; - any2scsi(icb.len, sizeof(buf)); - any2scsi(icb.ptr, (int) &buf); + any2scsi (icb.len, sizeof (buf)); + any2scsi (icb.ptr, (int) &buf); icb.phase = 1; /* * This routine is only called at init, so there should be OGMBs * available. I'm assuming so here. If this is going to * fail, I can just let the timeout catch the failure. */ - mail_out(host, (struct scb *) &icb); - timeout = jiffies + WAITnexttimeout; /* wait up to 2 seconds */ + mail_out (host, (struct scb *) &icb); + timeout = jiffies + WAITnexttimeout; /* wait up to 2 seconds */ while (icb.phase && jiffies < timeout) - barrier(); /* wait for completion */ + barrier (); /* wait for completion */ - if (icb.phase) { - printk("wd7000_diagnostics: timed out.\n"); - return 0; - } - if (make_code(icb.vue|(icb.status << 8),0)) { - printk("wd7000_diagnostics: failed (0x%02x,0x%02x)\n", - icb.vue, icb.status); - return 0; + if (icb.phase) { + printk ("wd7000_diagnostics: timed out.\n"); + return (0); + } + if (make_code (icb.vue | (icb.status << 8), 0)) { + printk ("wd7000_diagnostics: failed (0x%02x,0x%02x)\n", + icb.vue, icb.status); + return (0); } - return 1; + return (1); } -int wd7000_init( Adapter *host ) +int wd7000_init (Adapter *host) { - InitCmd init_cmd = { - INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, {0,0,0}, OGMB_CNT, ICMB_CNT + InitCmd init_cmd = + { + INITIALIZATION, + 7, + host->bus_on, + host->bus_off, + 0, + { 0, 0, 0 }, + OGMB_CNT, + ICMB_CNT }; int diag; @@ -1171,84 +1268,78 @@ * Reset the adapter - only. The SCSI bus was initialized at power-up, * and we need to do this just so we control the mailboxes, etc. */ - outb(ASC_RES, host->iobase+ASC_CONTROL); - delay(1); /* reset pulse: this is 10ms, only need 25us */ - outb(0,host->iobase+ASC_CONTROL); - host->control = 0; /* this must always shadow ASC_CONTROL */ - - if (WAIT (host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { - printk ("wd7000_init: WAIT timed out.\n"); - return 0; /* 0 = not ok */ - } - - if ((diag = inb(host->iobase+ASC_INTR_STAT)) != 1) { - printk("wd7000_init: "); - - switch (diag) { - case 2: - printk("RAM failure.\n"); - break; - case 3: - printk("FIFO R/W failed\n"); - break; - case 4: - printk("SBIC register R/W failed\n"); - break; - case 5: - printk("Initialization D-FF failed.\n"); - break; - case 6: - printk("Host IRQ D-FF failed.\n"); - break; - case 7: - printk("ROM checksum error.\n"); - break; - default: - printk("diagnostic code 0x%02Xh received.\n", diag); + outb (ASC_RES, host->iobase + ASC_CONTROL); + delay (1); /* reset pulse: this is 10ms, only need 25us */ + outb (0, host->iobase + ASC_CONTROL); + host->control = 0; /* this must always shadow ASC_CONTROL */ + + if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { + printk ("wd7000_init: WAIT timed out.\n"); + return (0); /* 0 = not ok */ + } + + if ((diag = inb (host->iobase + ASC_INTR_STAT)) != 1) { + printk ("wd7000_init: "); + + switch (diag) { + case 2: printk ("RAM failure.\n"); + break; + case 3: printk ("FIFO R/W failed\n"); + break; + case 4: printk ("SBIC register R/W failed\n"); + break; + case 5: printk ("Initialization D-FF failed.\n"); + break; + case 6: printk ("Host IRQ D-FF failed.\n"); + break; + case 7: printk ("ROM checksum error.\n"); + break; + default: printk ("diagnostic code 0x%02Xh received.\n", diag); } - return 0; + return (0); } - + /* Clear mailboxes */ - memset(&(host->mb), 0, sizeof(host->mb)); + memset (&(host->mb), 0, sizeof (host->mb)); /* Execute init command */ - any2scsi((unchar *) &(init_cmd.mailboxes), (int) &(host->mb)); - if (!command_out(host, (unchar *) &init_cmd, sizeof(init_cmd))) { - printk("wd7000_init: adapter initialization failed.\n"); - return 0; + any2scsi ((unchar *) & (init_cmd.mailboxes), (int) &(host->mb)); + if (!command_out (host, (unchar *) &init_cmd, sizeof (init_cmd))) { + printk ("wd7000_init: adapter initialization failed.\n"); + return (0); } - if (WAIT (host->iobase+ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) { - printk ("wd7000_init: WAIT timed out.\n"); - return 0; + if (WAIT (host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) { + printk ("wd7000_init: WAIT timed out.\n"); + return (0); } - if (request_irq(host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) { - printk("wd7000_init: can't get IRQ %d.\n", host->irq); - return 0; + if (request_irq (host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000", NULL)) { + printk ("wd7000_init: can't get IRQ %d.\n", host->irq); + return (0); } - if (request_dma(host->dma,"wd7000")) { - printk("wd7000_init: can't get DMA channel %d.\n", host->dma); - free_irq(host->irq, NULL); - return 0; + if (request_dma (host->dma, "wd7000")) { + printk ("wd7000_init: can't get DMA channel %d.\n", host->dma); + free_irq (host->irq, NULL); + return (0); } - wd7000_enable_dma(host); - wd7000_enable_intr(host); + wd7000_enable_dma (host); + wd7000_enable_intr (host); - if (!wd7000_diagnostics(host,ICB_DIAG_FULL)) { - free_dma(host->dma); - free_irq(host->irq, NULL); - return 0; + if (!wd7000_diagnostics (host, ICB_DIAG_FULL)) { + free_dma (host->dma); + free_irq (host->irq, NULL); + return (0); } - return 1; + return (1); } -void wd7000_revision(Adapter *host) +void wd7000_revision (Adapter *host) { - static IcbRevLvl icb = {ICB_OP_GET_REVISION}; + static IcbRevLvl icb = + {ICB_OP_GET_REVISION}; icb.phase = 1; /* @@ -1257,14 +1348,160 @@ * the only damage will be that the revision will show up as 0.0, * which in turn means that scatter/gather will be disabled. */ - mail_out(host, (struct scb *) &icb); + mail_out (host, (struct scb *) &icb); while (icb.phase) - barrier(); /* wait for completion */ + barrier (); /* wait for completion */ host->rev1 = icb.primary; host->rev2 = icb.secondary; } +#undef SPRINTF +#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } + +int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host) +{ + unsigned long flags; + + save_flags (flags); + cli (); + +#ifdef WD7000_DEBUG + printk ("Buffer = <%.*s>, length = %d\n", length, buffer, length); +#endif + + /* + * Currently this is a no-op + */ + printk ("Sorry, this function is currently out of order...\n"); + + restore_flags (flags); + + return (length); +} + + +int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout) +{ + struct Scsi_Host *host = NULL; + Scsi_Device *scd; + Adapter *adapter; + unsigned long flags; + char *pos = buffer; + short i; + +#ifdef WD7000_DEBUG + Mailbox *ogmbs, *icmbs; + short count; +#endif + + /* + * Find the specified host board. + */ + for (i = 0; i < IRQS; i++) + if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) { + host = wd7000_host[i]; + + break; + } + + /* + * Host not found! + */ + if (! host) + return (-ESRCH); + + /* + * Has data been written to the file ? + */ + if (inout) + return (wd7000_set_info (buffer, length, host)); + + adapter = (Adapter *) host->hostdata; + + save_flags (flags); + cli (); + + SPRINTF ("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2); + SPRINTF (" IO base: 0x%x\n", adapter->iobase); + SPRINTF (" IRQ: %d\n", adapter->irq); + SPRINTF (" DMA channel: %d\n", adapter->dma); + SPRINTF (" Interrupts: %d\n", adapter->int_counter); + SPRINTF (" BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125); + SPRINTF (" BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125); + +#ifdef WD7000_DEBUG + ogmbs = adapter->mb.ogmb; + icmbs = adapter->mb.icmb; + + SPRINTF ("\nControl port value: 0x%x\n", adapter->control); + SPRINTF ("Incoming mailbox:\n"); + SPRINTF (" size: %d\n", ICMB_CNT); + SPRINTF (" queued messages: "); + + for (i = count = 0; i < ICMB_CNT; i++) + if (icmbs[i].status) { + count++; + SPRINTF ("0x%x ", i); + } + + SPRINTF (count ? "\n" : "none\n"); + + SPRINTF ("Outgoing mailbox:\n"); + SPRINTF (" size: %d\n", OGMB_CNT); + SPRINTF (" next message: 0x%x\n", adapter->next_ogmb); + SPRINTF (" queued messages: "); + + for (i = count = 0; i < OGMB_CNT; i++) + if (ogmbs[i].status) { + count++; + SPRINTF ("0x%x ", i); + } + + SPRINTF (count ? "\n" : "none\n"); +#endif + + /* + * Display driver information for each device attached to the board. + */ + scd = host->host_queue; + + SPRINTF ("\nAttached devices: %s\n", scd ? "" : "none"); + + for ( ; scd; scd = scd->next) + if (scd->host->host_no == hostno) { + SPRINTF (" [Channel: %02d, Id: %02d, Lun: %02d] ", + scd->channel, scd->id, scd->lun); + SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ? + scsi_device_types[(short) scd->type] : "Unknown device"); + + for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++) + SPRINTF ("%c", scd->vendor[i]); + SPRINTF (" "); + + for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++) + SPRINTF ("%c", scd->model[i]); + SPRINTF ("\n"); + } + + SPRINTF ("\n"); + + restore_flags (flags); + + /* + * Calculate start of next buffer, and return value. + */ + *start = buffer + offset; + + if ((pos - buffer) < offset) + return (0); + else if ((pos - buffer - offset) < length) + return (pos - buffer - offset); + else + return (length); +} + + /* * Returns the number of adapters this driver is supporting. * @@ -1277,84 +1514,102 @@ */ int wd7000_detect (Scsi_Host_Template *tpnt) { - short present = 0, biosaddr_ptr, cfg_ptr, sig_ptr, i, pass; + short present = 0, biosaddr_ptr, sig_ptr, i, pass; short biosptr[NUM_CONFIGS]; unsigned iobase; Adapter *host = NULL; struct Scsi_Host *sh; - for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1); +#ifdef WD7000_DEBUG + printk ("wd7000_detect: started\n"); +#endif + + for (i = 0; i < IRQS; wd7000_host[i++] = NULL) ; + for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1) ; tpnt->proc_dir = &proc_scsi_wd7000; + tpnt->proc_info = &wd7000_proc_info; /* * Set up SCB free list, which is shared by all adapters */ init_scbs (); - for (pass = 0, cfg_ptr = 0; pass < NUM_CONFIGS; pass++) { - for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++) + for (pass = 0; pass < NUM_CONFIGS; pass++) { + /* + * First, search for BIOS SIGNATURE... + */ + for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++) for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) { - for (i = 0; i < pass; i++) - if (biosptr[i] == biosaddr_ptr) - break; - - if ((i == pass) && - check_signature(wd7000_biosaddr[biosaddr_ptr] + - signatures[sig_ptr].ofs, - signatures[sig_ptr].sig, - signatures[sig_ptr].len)) - goto bios_matched; - } + for (i = 0; i < pass; i++) + if (biosptr[i] == biosaddr_ptr) + break; -bios_matched: + if (i == pass) { +#if (LINUX_VERSION_CODE < 0x020100) +#else + void *biosaddr = ioremap (wd7000_biosaddr[biosaddr_ptr] + + signatures[sig_ptr].ofs, + signatures[sig_ptr].len); +#endif + short bios_match = memcmp ((char *) biosaddr, signatures[sig_ptr].sig, + signatures[sig_ptr].len); + +#if (LINUX_VERSION_CODE < 0x020100) +#else + iounmap (biosaddr); +#endif -#ifdef DEBUG + if (! bios_match) + goto bios_matched; + } + } + + bios_matched: + /* + * BIOS SIGNATURE has been found. + */ +#ifdef WD7000_DEBUG printk ("wd7000_detect: pass %d\n", pass + 1); - if (biosaddr_ptr == NUM_ADDRS) + if (biosaddr_ptr == NUM_ADDRS) printk ("WD-7000 SST BIOS not detected...\n"); else printk ("WD-7000 SST BIOS detected at 0x%lx: checking...\n", - wd7000_biosaddr[biosaddr_ptr]); + wd7000_biosaddr[biosaddr_ptr]); #endif - if (wd7000_card_num) - iobase = wd7000_setupIO[wd7000_card_num - 1]; - else { - if (configs[cfg_ptr++].irq < 0) - continue; + if (configs[pass].irq < 0) + continue; - iobase = configs[cfg_ptr - 1].iobase; - } + iobase = configs[pass].iobase; -#ifdef DEBUG - printk ("wd7000_detect: check IO 0x%x region...\n", iobase); +#ifdef WD7000_DEBUG + printk ("wd7000_detect: check IO 0x%x region...\n", iobase); #endif - if (! check_region (iobase, 4)) { + if (!check_region (iobase, 4)) { -#ifdef DEBUG - printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase); +#ifdef WD7000_DEBUG + printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase); #endif - - /* - * ASC reset... - */ - outb (ASC_RES, iobase + ASC_CONTROL); - delay (1); - outb (0, iobase + ASC_CONTROL); - - if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) -#ifdef DEBUG - { - printk ("failed!\n"); - continue; - } - else - printk ("ok!\n"); + /* + * ASC reset... + */ + outb (ASC_RES, iobase + ASC_CONTROL); + delay (1); + outb (0, iobase + ASC_CONTROL); + + if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) +#ifdef WD7000_DEBUG + { + printk ("failed!\n"); + continue; + } + else + printk ("ok!\n"); #else - continue; + continue; #endif if (inb (iobase + ASC_INTR_STAT) == 1) { @@ -1368,33 +1623,27 @@ sh = scsi_register (tpnt, sizeof (Adapter)); host = (Adapter *) sh->hostdata; -#ifdef DEBUG - printk ("wd7000_detect: adapter allocated at 0x%x\n", - (int) host); +#ifdef WD7000_DEBUG + printk ("wd7000_detect: adapter allocated at 0x%x\n", (int) host); #endif memset (host, 0, sizeof (Adapter)); - if (wd7000_card_num) { - host->irq = wd7000_setupIRQ[--wd7000_card_num]; - host->dma = wd7000_setupDMA[wd7000_card_num]; - } - else { - host->irq = configs[cfg_ptr - 1].irq; - host->dma = configs[cfg_ptr - 1].dma; - } - - host->sh = sh; - host->iobase = iobase; - irq2host[host->irq] = host; + host->irq = configs[pass].irq; + host->dma = configs[pass].dma; + host->iobase = iobase; + host->int_counter = 0; + host->bus_on = configs[pass].bus_on; + host->bus_off = configs[pass].bus_off; + host->sh = wd7000_host[host->irq - IRQ_MIN] = sh; -#ifdef DEBUG +#ifdef WD7000_DEBUG printk ("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma); #endif - if (! wd7000_init (host)) { /* Initialization failed */ + if (!wd7000_init (host)) { /* Initialization failed */ scsi_unregister (sh); continue; @@ -1403,7 +1652,7 @@ /* * OK from here - we'll use this adapter/configuration. */ - wd7000_revision (host); /* important for scatter/gather */ + wd7000_revision (host); /* important for scatter/gather */ /* * Register our ports. @@ -1411,34 +1660,34 @@ request_region (host->iobase, 4, "wd7000"); /* - * For boards before rev 6.0, scatter/gather - * isn't supported. + * For boards before rev 6.0, scatter/gather isn't supported. */ if (host->rev1 < 6) sh->sg_tablesize = SG_NONE; - present++; /* count it */ + present++; /* count it */ if (biosaddr_ptr != NUM_ADDRS) biosptr[pass] = biosaddr_ptr; printk ("Western Digital WD-7000 (rev %d.%d) ", host->rev1, host->rev2); - printk ("using IO 0x%x, IRQ %d, DMA %d.\n", + printk ("using IO 0x%x, IRQ %d, DMA %d.\n", host->iobase, host->irq, host->dma); + printk (" BUS_ON time: %dns, BUS_OFF time: %dns\n", + host->bus_on * 125, host->bus_off * 125); } } -#ifdef DEBUG +#ifdef WD7000_DEBUG else - printk ("wd7000_detect: IO 0x%x region already allocated!\n", - iobase); + printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase); #endif } - if (! present) - printk ("Failed initialization of WD-7000 SCSI card!\n"); + if (!present) + printk ("Failed initialization of WD-7000 SCSI card!\n"); return (present); } @@ -1447,42 +1696,81 @@ /* * I have absolutely NO idea how to do an abort with the WD7000... */ -int wd7000_abort(Scsi_Cmnd * SCpnt) +int wd7000_abort (Scsi_Cmnd *SCpnt) { Adapter *host = (Adapter *) SCpnt->host->hostdata; - if (inb(host->iobase+ASC_STAT) & INT_IM) { - printk("wd7000_abort: lost interrupt\n"); - wd7000_intr_handle(host->irq, NULL, NULL); - return SCSI_ABORT_SUCCESS; + if (inb (host->iobase + ASC_STAT) & INT_IM) { + printk ("wd7000_abort: lost interrupt\n"); + wd7000_intr_handle (host->irq, NULL, NULL); + + return (SCSI_ABORT_SUCCESS); } - return SCSI_ABORT_SNOOZE; + return (SCSI_ABORT_SNOOZE); } /* * I also have no idea how to do a reset... */ -int wd7000_reset(Scsi_Cmnd * SCpnt, unsigned int ignored) +int wd7000_reset (Scsi_Cmnd *SCpnt, unsigned int unused) { - return SCSI_RESET_PUNT; + return (SCSI_RESET_PUNT); } /* - * This was borrowed directly from aha1542.c, but my disks are organized - * this way, so I think it will work OK. Someone who is ambitious can - * borrow a newer or more complete version from another driver. + * This was borrowed directly from aha1542.c. (Zaga) */ -int wd7000_biosparam(Disk * disk, kdev_t dev, int* ip) +int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip) { - int size = disk->capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; -/* if (ip[2] >= 1024) ip[2] = 1024; */ - return 0; +#ifdef WD7000_DEBUG + printk ("wd7000_biosparam: dev=%s, size=%d, ", kdevname (dev), disk->capacity); +#endif + + /* + * try default translation + */ + ip[0] = 64; + ip[1] = 32; + ip[2] = disk->capacity / (64 * 32); + + /* + * for disks >1GB do some guessing + */ + if (ip[2] >= 1024) { + int info[3]; + + /* + * try to figure out the geometry from the partition table + */ + if ((scsicam_bios_param (disk, dev, info) < 0) || + !(((info[0] == 64) && (info[1] == 32)) || + ((info[0] == 255) && (info[1] == 63)))) { + printk ("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" + " using extended translation.\n"); + + ip[0] = 255; + ip[1] = 63; + ip[2] = disk->capacity / (255 * 63); + } + else { + ip[0] = info[0]; + ip[1] = info[1]; + ip[2] = info[2]; + + if (info[0] == 255) + printk ("wd7000_biosparam: current partition table is using extended translation.\n"); + } + } + +#ifdef WD7000_DEBUG + printk ("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]); + printk ("WARNING: check, if the bios geometry is correct.\n"); +#endif + + return (0); } #ifdef MODULE diff -ur --new-file old/linux/drivers/scsi/wd7000.h new/linux/drivers/scsi/wd7000.h --- old/linux/drivers/scsi/wd7000.h Mon Dec 22 02:04:49 1997 +++ new/linux/drivers/scsi/wd7000.h Tue Mar 10 19:20:58 1998 @@ -8,17 +8,23 @@ * This file has been reduced to only the definitions needed for the * WD7000 host structure. * + * Revision by Miroslav Zagorac Jun 1997. */ #include #include -int wd7000_detect(Scsi_Host_Template *); -int wd7000_command(Scsi_Cmnd *); -int wd7000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -int wd7000_abort(Scsi_Cmnd *); -int wd7000_reset(Scsi_Cmnd *, unsigned int); -int wd7000_biosparam(Disk *, kdev_t, int *); +extern struct proc_dir_entry proc_scsi_wd7000; + + +int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host); +int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout); +int wd7000_detect (Scsi_Host_Template *); +int wd7000_command (Scsi_Cmnd *); +int wd7000_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int wd7000_abort (Scsi_Cmnd *); +int wd7000_reset (Scsi_Cmnd *, unsigned int); +int wd7000_biosparam (Disk *, kdev_t, int *); #ifndef NULL #define NULL 0L @@ -38,18 +44,22 @@ #define WD7000_Q 16 #define WD7000_SG 16 -#define WD7000 { \ - name: "Western Digital WD-7000", \ - detect: wd7000_detect, \ - command: wd7000_command, \ - queuecommand: wd7000_queuecommand, \ - abort: wd7000_abort, \ - reset: wd7000_reset, \ - bios_param: wd7000_biosparam, \ - can_queue: WD7000_Q, \ - this_id: 7, \ - sg_tablesize: WD7000_SG, \ - cmd_per_lun: 1, \ - unchecked_isa_dma: 1, \ - use_clustering: ENABLE_CLUSTERING} +#define WD7000 { \ + proc_dir: &proc_scsi_wd7000, \ + proc_info: wd7000_proc_info, \ + name: "Western Digital WD-7000", \ + detect: wd7000_detect, \ + command: wd7000_command, \ + queuecommand: wd7000_queuecommand, \ + abort: wd7000_abort, \ + reset: wd7000_reset, \ + bios_param: wd7000_biosparam, \ + can_queue: WD7000_Q, \ + this_id: 7, \ + sg_tablesize: WD7000_SG, \ + cmd_per_lun: 1, \ + unchecked_isa_dma: 1, \ + use_clustering: ENABLE_CLUSTERING, \ + use_new_eh_code: 0 \ +} #endif diff -ur --new-file old/linux/drivers/sgi/char/sgiserial.c new/linux/drivers/sgi/char/sgiserial.c --- old/linux/drivers/sgi/char/sgiserial.c Wed Dec 10 19:31:11 1997 +++ new/linux/drivers/sgi/char/sgiserial.c Sat Feb 21 03:28:22 1998 @@ -3,6 +3,7 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ +#include /* for CONFIG_REMOTE_DEBUG */ #include #include #include diff -ur --new-file old/linux/drivers/sgi/char/shmiq.c new/linux/drivers/sgi/char/shmiq.c --- old/linux/drivers/sgi/char/shmiq.c Wed Dec 10 19:31:11 1997 +++ new/linux/drivers/sgi/char/shmiq.c Fri Feb 27 18:12:29 1998 @@ -365,7 +365,7 @@ if (!shmiqs [minor].mapped) return 0; - poll_wait (&shmiqs [minor].proc_list, wait); + poll_wait (filp, &shmiqs [minor].proc_list, wait); s = shmiqs [minor].shmiq_vaddr; if (s->head != s->tail) return POLLIN | POLLRDNORM; diff -ur --new-file old/linux/drivers/sound/Config.in new/linux/drivers/sound/Config.in --- old/linux/drivers/sound/Config.in Mon Jan 12 23:46:21 1998 +++ new/linux/drivers/sound/Config.in Sat Mar 14 00:36:03 1998 @@ -1,19 +1,21 @@ dep_tristate 'ProAudioSpectrum 16 support' CONFIG_PAS $CONFIG_SOUND if [ "$CONFIG_PAS" = "y" ]; then - int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10 - int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3 + int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10 + int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' CONFIG_PAS_DMA 3 fi dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND if [ "$CONFIG_SB" = "y" ]; then - hex 'I/O base for SB Check from manual of the card' SBC_BASE 220 - int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7 - int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1 - int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5 - hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330 + bool 'Is the card a Soundman Games ?' CONFIG_SM_GAMES + bool 'Are you using the IBM Mwave "emulation" of SB ?' CONFIG_SB_MWAVE + hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220 + int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7 + int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1 + int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' CONFIG_SB_DMA2 5 + hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' CONFIG_SB_MPU_BASE 330 comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.' comment 'Enter -1 to the following question if you have something else such as SB16/32.' - int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1 + int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1 fi dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB $CONFIG_SOUND @@ -23,124 +25,125 @@ bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 bool 'GUS MAX support' CONFIG_GUSMAX if [ "$CONFIG_GUS" = "y" ]; then - hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220 - int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15 - int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6 - int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1 + hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' CONFIG_GUS_BASE 220 + int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' CONFIG_GUS_IRQ 15 + int 'GUS DMA 1, 3, 5, 6 or 7' CONFIG_GUS_DMA 6 + int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' CONFIG_GUS_DMA2 -1 if [ "$CONFIG_GUS16" = "y" ]; then - hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530 - int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7 - int 'GUS DMA 0, 1 or 3' GUS16_DMA 3 + hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' CONFIG_GUS16_BASE 530 + int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' CONFIG_GUS16_IRQ 7 + int 'GUS DMA 0, 1 or 3' CONFIG_GUS16_DMA 3 fi fi fi dep_tristate 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 $CONFIG_SOUND if [ "$CONFIG_MPU401" = "y" ]; then - hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330 - int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9 + hex 'I/O base for MPU401 Check from manual of the card' CONFIG_MPU_BASE 330 + int 'MPU401 IRQ Check from manual of the card' CONFIG_MPU_IRQ 9 fi dep_tristate 'PSS (ECHO-ADI2111) support' CONFIG_PSS $CONFIG_SOUND if [ "$CONFIG_PSS" = "y" ]; then - hex 'PSS I/O base 220 or 240' PSS_BASE 220 - hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530 - int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11 - int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3 - hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330 - int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9 - bool ' Have DSPxxx.LD firmware file' PSS_HAVE_BOOT - if [ "$PSS_HAVE_BOOT" = "y" ]; then - string ' Full pathname of DSPxxx.LD firmware file' PSS_BOOT_FILE + hex 'PSS I/O base 220 or 240' CONFIG_PSS_BASE 220 + hex 'PSS audio I/O base 530, 604, E80 or F40' CONFIG_PSS_MSS_BASE 530 + int 'PSS audio IRQ 7, 9, 10 or 11' CONFIG_PSS_MSS_IRQ 11 + int 'PSS audio DMA 0, 1 or 3' CONFIG_PSS_MSS_DMA 3 + hex 'PSS MIDI I/O base ' CONFIG_PSS_MPU_BASE 330 + int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_PSS_MPU_IRQ 9 + bool ' Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT + if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then + string ' Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE fi fi dep_tristate 'Microsoft Sound System support' CONFIG_MSS $CONFIG_SOUND if [ "$CONFIG_MSS" = "y" ]; then - hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530 - int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11 - int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3 - int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1 + 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 + int 'MSS/WSS second DMA (if possible) 0, 1 or 3' CONFIG_MSS_DMA2 -1 fi dep_tristate 'Ensoniq SoundScape support' CONFIG_SSCAPE $CONFIG_SOUND if [ "$CONFIG_SSCAPE" = "y" ]; then - hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330 - int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9 - int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3 - hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534 - int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11 + hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' CONFIG_SSCAPE_BASE 330 + int 'SoundScape MIDI IRQ ' CONFIG_SSCAPE_IRQ 9 + int 'SoundScape initialization DMA 0, 1 or 3' CONFIG_SSCAPE_DMA 3 + hex 'SoundScape audio I/O base 534, 608, E84 or F44' CONFIG_SSCAPE_MSS_BASE 534 + int 'SoundScape audio IRQ 7, 9, 10 or 11' CONFIG_SSCAPE_MSS_IRQ 11 fi dep_tristate 'MediaTrix AudioTrix Pro support' CONFIG_TRIX $CONFIG_SOUND if [ "$CONFIG_TRIX" = "y" ]; then - hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' TRIX_BASE 530 - int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11 - int 'OPL3-SA1 audio DMA 0, 1 or 3' TRIX_DMA 0 - int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3 - hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330 - int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9 - hex 'OPL3-SA1 SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220 - int 'OPL3-SA1 SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7 - int 'OPL3-SA1 SB DMA 1 or 3' TRIX_SB_DMA 1 - bool ' Have TRXPRO.HEX firmware file' TRIX_HAVE_BOOT - if [ "$TRIX_HAVE_BOOT" = "y" ]; then - string ' Full pathname of TRXPRO.HEX firmware file' TRIX_BOOT_FILE + hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_TRIX_BASE 530 + int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_TRIX_IRQ 11 + int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_TRIX_DMA 0 + int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' CONFIG_TRIX_DMA2 3 + hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_TRIX_MPU_BASE 330 + int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_TRIX_MPU_IRQ 9 + hex 'OPL3-SA1 SB I/O base 220, 210, 230, 240, 250, 260 or 270' CONFIG_TRIX_SB_BASE 220 + int 'OPL3-SA1 SB IRQ 3, 4, 5 or 7' CONFIG_TRIX_SB_IRQ 7 + int 'OPL3-SA1 SB DMA 1 or 3' CONFIG_TRIX_SB_DMA 1 + bool ' Have TRXPRO.HEX firmware file' CONFIG_TRIX_HAVE_BOOT + if [ "$CONFIG_TRIX_HAVE_BOOT" = "y" ]; then + string ' Full pathname of TRXPRO.HEX firmware file' CONFIG_TRIX_BOOT_FILE fi fi dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_MAD16 $CONFIG_SOUND if [ "$CONFIG_MAD16" = "y" ]; then - hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530 - int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11 - int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3 - int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0 - hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330 - int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9 + hex 'MAD16 audio I/O base 530, 604, E80 or F40' CONFIG_MAD16_BASE 530 + int 'MAD16 audio IRQ 7, 9, 10 or 11' CONFIG_MAD16_IRQ 11 + int 'MAD16 audio DMA 0, 1 or 3' CONFIG_MAD16_DMA 3 + int 'MAD16 second (duplex) DMA 0, 1 or 3' CONFIG_MAD16_DMA2 0 + hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' CONFIG_MAD16_MPU_BASE 330 + int 'MAD16 MIDI IRQ 5, 7, 9 or 10' CONFIG_MAD16_MPU_IRQ 9 fi dep_tristate 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 $CONFIG_SOUND if [ "$CONFIG_CS4232" = "y" ]; then - hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530 - int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11 - int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0 - int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3 - hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330 - int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9 + hex 'CS4232 audio I/O base 530, 604, E80 or F40' CONFIG_CS4232_BASE 530 + int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_IRQ 11 + int 'CS4232 audio DMA 0, 1 or 3' CONFIG_CS4232_DMA 0 + int 'CS4232 second (duplex) DMA 0, 1 or 3' CONFIG_CS4232_DMA2 3 + hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_CS4232_MPU_BASE 330 + int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_MPU_IRQ 9 fi dep_tristate 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI $CONFIG_SOUND if [ "$CONFIG_MAUI" = "y" ]; then - hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330 - int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9 - bool ' Have OSWF.MOT firmware file' MAUI_HAVE_BOOT - if [ "$MAUI_HAVE_BOOT" = "y" ]; then - string ' Full pathname of OSWF.MOT firmware file' MAUI_BOOT_FILE + hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_MAUI_BASE 330 + int 'Maui IRQ 5, 9, 12 or 15' CONFIG_MAUI_IRQ 9 + bool ' Have OSWF.MOT firmware file' CONFIG_MAUI_HAVE_BOOT + if [ "$CONFIG_MAUI_HAVE_BOOT" = "y" ]; then + string ' Full pathname of OSWF.MOT firmware file' CONFIG_MAUI_BOOT_FILE fi fi dep_tristate 'Yamaha OPL3-SA1 audio controller' CONFIG_OPL3SA1 $CONFIG_SOUND if [ "$CONFIG_OPL3SA1" = "y" ]; then - hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' OPL3SA1_BASE 530 - int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' OPL3SA1_IRQ 11 - int 'OPL3-SA1 audio DMA 0, 1 or 3' OPL3SA1_DMA 0 - int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' OPL3SA1_DMA2 3 - hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' OPL3SA1_MPU_BASE 330 - int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' OPL3SA1_MPU_IRQ 9 + hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA1_BASE 530 + int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_OPL3SA1_IRQ 11 + int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA 0 + int 'OPL3-SA1 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA2 3 + hex 'OPL3-SA1 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_OPL3SA1_MPU_BASE 330 + int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_OPL3SA1_MPU_IRQ 9 fi dep_tristate 'SoftOSS software wave table engine' CONFIG_SOFTOSS $CONFIG_SOUND if [ "$CONFIG_SOFTOSS" = "y" ]; then - int 'Sampling rate for SoftOSS 8000 to 48000' SOFTOSS_RATE 22050 - int 'Max # of concurrent voices for SoftOSS 4 to 32' SOFTOSS_VOICES 32 + int 'Sampling rate for SoftOSS 8000 to 48000' CONFIG_SOFTOSS_RATE 22050 + int 'Max # of concurrent voices for SoftOSS 4 to 32' CONFIG_SOFTOSS_VOICES 32 fi dep_tristate 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 $CONFIG_SOUND dep_tristate 'Loopback MIDI device support' CONFIG_VMIDI $CONFIG_SOUND +dep_tristate '6850 UART support' CONFIG_UART6850 $CONFIG_SOUND if [ "$CONFIG_UART6850" = "y" ]; then - hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0 - int 'UART6850 IRQ (Unknown)' U6850_IRQ -1 + hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0 + int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1 fi @@ -152,7 +155,7 @@ dep_tristate 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then - hex ' I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220 + hex ' I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220 fi if [ "$CONFIG_AEDSP16" = "y" ]; then @@ -164,10 +167,10 @@ if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then comment 'Audio Excel DSP 16 [Sound Blaster Pro]' hex 'I/O base for Audio Excel DSP 16 220 or 240' \ - AEDSP16_BASE $SBC_BASE + CONFIG_AEDSP16_BASE $CONFIG_SB_BASE int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \ - AEDSP16_SBC_IRQ $SBC_IRQ - int 'Audio Excel DSP 16 DMA 0, 1 or 3' AEDSP16_SBC_DMA $SBC_DMA + CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ + int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA fi fi @@ -175,10 +178,10 @@ bool 'Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then comment 'Audio Excel DSP 16 [Microsoft Sound System]' - hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220 + hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220 int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \ - AEDSP16_MSS_IRQ $MSS_IRQ - int 'Audio Excel DSP 16 DMA 0, 1 or 3' AEDSP16_MSS_DMA $MSS_DMA + CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ + int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA fi fi @@ -188,10 +191,10 @@ comment 'Audio Excel DSP 16 [MPU-401]' if [ "$CONFIG_AEDSP16_SBPRO" != "y" \ -a "$CONFIG_AEDSP16_MSS" != "y" ]; then - hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220 + hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220 fi int 'MPU401 IRQ for Audio Excel DSP 16 5, 7, 9, 10 or 0 (disable)' \ - AEDSP16_MPU_IRQ $MPU_IRQ + CONFIG_AEDSP16_MPU_IRQ $CONFIG_MPU_IRQ fi fi fi diff -ur --new-file old/linux/drivers/sound/Defines new/linux/drivers/sound/Defines --- old/linux/drivers/sound/Defines Tue Dec 23 22:52:02 1997 +++ new/linux/drivers/sound/Defines Thu Feb 19 23:46:14 1998 @@ -97,10 +97,18 @@ endif endif -ifdef CONFIG_SB -ifneq ($(CONFIG_UART401),Y) -CONFIG_UART401=y -endif + + +ifdef CONFIG_SB + ifeq ($(CONFIG_SB),m) + ifneq ($(CONFIG_UART401),Y) + CONFIG_UART401=m + endif + else + ifneq ($(CONFIG_UART401),Y) + CONFIG_UART401=y + endif + endif endif ifdef CONFIG_TRIX @@ -118,18 +126,6 @@ ifdef CONFIG_OPL3SA1 ifneq ($(CONFIG_UART401),Y) CONFIG_UART401=y -endif -endif - -ifdef CONFIG_GUS -ifneq ($(CONFIG_GUSHW),Y) -CONFIG_GUSHW=y -endif -endif - -ifdef CONFIG_SSCAPE -ifneq ($(CONFIG_SSCAPEHW),Y) -CONFIG_SSCAPEHW=y endif endif diff -ur --new-file old/linux/drivers/sound/Makefile new/linux/drivers/sound/Makefile --- old/linux/drivers/sound/Makefile Sun Jan 4 19:40:16 1998 +++ new/linux/drivers/sound/Makefile Sat Mar 14 21:07:42 1998 @@ -117,22 +117,6 @@ endif endif -ifeq ($(CONFIG_MPU401),y) -LX_OBJS += mpu401.o -else - ifeq ($(CONFIG_MPU401),m) - MX_OBJS += mpu401.o - else - ifeq ($(CONFIG_MPU_EMU),y) - LX_OBJS += mpu401.o - else - ifeq ($(CONFIG_MPU_EMU),m) - MX_OBJS += mpu401.o - endif - endif - endif -endif - ifeq ($(CONFIG_UART401),y) LX_OBJS += uart401.o else @@ -159,9 +143,31 @@ ifeq ($(CONFIG_SSCAPE),y) L_OBJS += sscape.o +LX_OBJS += ad1848.o +CONFIG_MPU401 = y else ifeq ($(CONFIG_SSCAPE),m) M_OBJS += sscape.o + MX_OBJS += ad1848.o + ifneq ($(CONFIG_MPU401),y) + CONFIG_MPU401 = m + endif + endif +endif + +ifeq ($(CONFIG_MPU401),y) +LX_OBJS += mpu401.o +else + ifeq ($(CONFIG_MPU401),m) + MX_OBJS += mpu401.o + else + ifeq ($(CONFIG_MPU_EMU),y) + LX_OBJS += mpu401.o + else + ifeq ($(CONFIG_MPU_EMU),m) + MX_OBJS += mpu401.o + endif + endif endif endif @@ -258,48 +264,48 @@ hex2hex: hex2hex.c $(HOSTCC) -o hex2hex hex2hex.c -ifeq ($(MAUI_HAVE_BOOT),y) +ifeq ($(CONFIG_MAUI_HAVE_BOOT),y) -MAUI_BOOT_FILE := $(patsubst "%", %, $(MAUI_BOOT_FILE)) +CONFIG_MAUI_BOOT_FILE := $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) maui.o: maui_boot.h -maui_boot.h: $(MAUI_BOOT_FILE) bin2hex - bin2hex maui_os < "$(MAUI_BOOT_FILE)" > $@ +maui_boot.h: $(CONFIG_MAUI_BOOT_FILE) bin2hex + bin2hex -i maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@ @ ( \ - echo 'ifeq ($(strip $(MAUI_BOOT_FILE)),$$(strip $$(MAUI_BOOT_FILE)))'; \ + echo 'ifeq ($(strip $(CONFIG_MAUI_BOOT_FILE)),$$(strip $$(CONFIG_MAUI_BOOT_FILE)))'; \ echo 'FILES_BOOT_UP_TO_DATE += $@'; \ echo 'endif' \ ) > .$@.boot endif -ifeq ($(PSS_HAVE_BOOT),y) +ifeq ($(CONFIG_PSS_HAVE_BOOT),y) -PSS_BOOT_FILE := $(patsubst "%", %, $(PSS_BOOT_FILE)) +CONFIG_PSS_BOOT_FILE := $(patsubst "%", %, $(CONFIG_PSS_BOOT_FILE)) pss.o: pss_boot.h -pss_boot.h: $(PSS_BOOT_FILE) bin2hex - bin2hex pss_synth < "$(PSS_BOOT_FILE)" > $@ +pss_boot.h: $(CONFIG_PSS_BOOT_FILE) bin2hex + bin2hex pss_synth < "$(CONFIG_PSS_BOOT_FILE)" > $@ @ ( \ - echo 'ifeq ($(strip $(PSS_BOOT_FILE)),$$(strip $$(PSS_BOOT_FILE)))'; \ + echo 'ifeq ($(strip $(CONFIG_PSS_BOOT_FILE)),$$(strip $$(CONFIG_PSS_BOOT_FILE)))'; \ echo 'FILES_BOOT_UP_TO_DATE += $@'; \ echo 'endif' \ ) > .$@.boot endif -ifeq ($(TRIX_HAVE_BOOT),y) +ifeq ($(CONFIG_TRIX_HAVE_BOOT),y) -TRIX_BOOT_FILE := $(patsubst "%", %, $(TRIX_BOOT_FILE)) +CONFIG_TRIX_BOOT_FILE := $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE)) trix.o: trix_boot.h -trix_boot.h: $(TRIX_BOOT_FILE) hex2hex - hex2hex trix_boot < "$(TRIX_BOOT_FILE)" > $@ +trix_boot.h: $(CONFIG_TRIX_BOOT_FILE) hex2hex + hex2hex -i trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@ @ ( \ - echo 'ifeq ($(strip $(TRIX_BOOT_FILE)),$$(strip $$(strip $$(TRIX_BOOT_FILE)))'; \ + echo 'ifeq ($(strip $(CONFIG_TRIX_BOOT_FILE)),$$(strip $$(CONFIG_TRIX_BOOT_FILE)))'; \ echo 'FILES_BOOT_UP_TO_DATE += $@'; \ echo 'endif' \ ) > .$@.boot diff -ur --new-file old/linux/drivers/sound/Readme.cards new/linux/drivers/sound/Readme.cards --- old/linux/drivers/sound/Readme.cards Tue Dec 23 22:52:02 1997 +++ new/linux/drivers/sound/Readme.cards Sun Feb 15 21:10:12 1998 @@ -3,7 +3,7 @@ This document describes configuring soundcards with freeware version of Open Sound Systems (OSS/Free). Information about the commercial version -(OSS/Linux) and it's configuration is available from +(OSS/Linux) and its configuration is available from http://www.opensound.com/linux.html. Information presented here is not valid for OSS/Linux. @@ -67,7 +67,7 @@ 2. Trying to use a PnP (Plug & Play) card just like an ordinary soundcard ------------------------------------------------------------------------- -Plug & Play is a protocol defined by Intel and Microsoft. It let's operating +Plug & Play is a protocol defined by Intel and Microsoft. It lets operating systems to easily identify and reconfigure I/O ports, IRQs and DMAs of ISA cards. The problem with PnP cards is that the standard Linux doesn't currently (versions 2.1.x and earlier) don't support PnP. This means that you will have @@ -293,25 +293,26 @@ 4Front Technologies SoftOSS SoftOSS is a software based wave table emulation which works with - any 16 bit stereo soundcard. Due to it's nature a fast CPU is - required (P133 is minumum). Althoug SoftOSS doesn _not_ use MMX + any 16 bit stereo soundcard. Due to its nature a fast CPU is + required (P133 is minimum). Although SoftOSS does _not_ use MMX instructions it has proven out that recent processors (which appear to have MMX) perform significantly better with SoftOSS than earlier ones. For example a P166MMX beats a PPro200. SoftOSS should not be used on 486 or 386 machines. - The amount of CPU load caused by SoftOSS can be controlled by - selecting the SOFTOSS_RATE and SOFTOSS_VOICES parameters properly - (they will be prompted by make config). It's recommended to set - SOFTOSS_VOICES to 32. If you have a P166MMX or faster (PPro200 is - not faster) you can set SOFTOSS_RATE to 44100 (kHz). However with - slower systems it recommended to use sampling rates around 22050 - or even 16000 kHz. Selecting too high values for these parameters - may hang your system when playing MIDI files with hight degree of - polyphony (number of concurrently playing notes). It's also possible to - decrease SOFTOSS_VOICES. This makes it possible to use higher sampling - rates. However using fewer voices decreases playback quality more than - decreasing the sampling rate. + The amount of CPU load caused by SoftOSS can be controlled by + selecting the CONFIG_SOFTOSS_RATE and CONFIG_SOFTOSS_VOICES + parameters properly (they will be prompted by make config). It's + recommended to set CONFIG_SOFTOSS_VOICES to 32. If you have a + P166MMX or faster (PPro200 is not faster) you can set + CONFIG_SOFTOSS_RATE to 44100 (kHz). However with slower systems it + recommended to use sampling rates around 22050 or even 16000 kHz. + Selecting too high values for these parameters may hang your + system when playing MIDI files with hight degree of polyphony + (number of concurrently playing notes). It's also possible to + decrease CONFIG_SOFTOSS_VOICES. This makes it possible to use + higher sampling rates. However using fewer voices decreases + playback quality more than decreasing the sampling rate. SoftOSS keeps the samples loaded on system's RAM so large RAM is required. SoftOSS should never be used on machines with less than 16M @@ -330,7 +331,7 @@ ********************************************************************* IMPORTANT NOTICE! The original patch set distributed with Gravis - Ultrasound card is not in public domain (even it's available from + Ultrasound card is not in public domain (even though it's available from some ftp sites). You should contact Voice Crystal (www.voicecrystal.com) if you like to use these patches with SoftOSS included in OSS/Free. ********************************************************************* @@ -1125,9 +1126,9 @@ The following configuration parameters have worked fine for the PCM12 in Markus Kuhn's system, many other configurations might work, too: -MAD16_BASE=0x530, MAD16_IRQ=11, MAD16_DMA=3, MAD16_DMA2=0, -MAD16_MPU_BASE=0x330, MAD16_MPU_IRQ=10, DSP_BUFFSIZE=65536, -SELECTED_SOUND_OPTIONS=0x00281000. +CONFIG_MAD16_BASE=0x530, CONFIG_MAD16_IRQ=11, CONFIG_MAD16_DMA=3, +CONFIG_MAD16_DMA2=0, CONFIG_MAD16_MPU_BASE=0x330, CONFIG_MAD16_MPU_IRQ=10, +DSP_BUFFSIZE=65536, SELECTED_SOUND_OPTIONS=0x00281000. The miroSOUND PCM1 pro and the PCM20 are very similar to the PCM12. Perhaps the same ACI driver also works for these cards, however this diff -ur --new-file old/linux/drivers/sound/Readme.modules new/linux/drivers/sound/Readme.modules --- old/linux/drivers/sound/Readme.modules Tue Sep 30 17:46:46 1997 +++ new/linux/drivers/sound/Readme.modules Sun Feb 15 21:10:12 1998 @@ -1,84 +1,71 @@ -Building a loadable sound driver +Building a modular sound driver ================================ -Loadable module support in version 3.5 of the driver is mostly rewritten since -the previous version (3.0.1). This means that some things have changed. - -To compile the sound driver as a loadable module you have to perform -the following steps: - -1) Install modules-1.2.8.tar.gz package (or later if available). -2a) Check that symbol remap_page_range is defined in linux/init/ksyms.c. -Insert a line containing "X(remap_page_range)," if required. The driver will -not load if this line is missing. -2b) Recompile kernel with soundcard support disabled. -3) Boot the new kernel. -4) cd to the sound driver source directory (this directory). It's no -longer required that the sound driver sources are installed in the -kernel source tree (linux/drivers/sound). When installing a separately -distributed sound driver you may install the sources for example to -/usr/src/sound. -5) Execute make in the sound driver source directory. Enter -configuration parameters as described in Readme.cards. Then just wait until -the driver is compiled OK. -6) Copy sound.o to the directory where insmod expects to find it. -("make install" copies it to /lib/modules/misc). -7) Use command "insmod sound" to load the driver. - -8) The sound driver can be removed using command "rmmod sound". - - -Parameters accepted by the loadable sound driver -================================================ - -Setting DMA buffer size ------------------------ - -The driver allocates a DMA buffer (or two for full duplex devices) -every time the audio device (/dev/dsp or /dev/audio) is opened -and frees it when the device is closed. Size of this buffer is defined -when the driver is configured (the last question). The buffer size -can be redefined when loading the driver if required (note that this is -an optional feature which is not normally required). The buffer size -is redefined by adding dma_pagesize= parameter to the insmod command line. -For example: - - insmod sound dma_buffsize=32768 - -Minimum buffer size is 4096 and the maximum depends on the DMA channel. -For 8 bit channels (0 to 3) the limit is 64k and for 16 bit ones (5 to 7) -it's 128k. Driver selects a suitable buffer size automatically in case -you try to specify an invalid size. - -Q: What is the right DMA buffer size? - -A: It depends on the sampling rate, machine speed and the load of the system. -Large buffers are required on slow machines, when recording/playing CD-quality -audio or when there are other processes running on the same system. Also -recording to hard disk is likely to require large buffers. - -Very small buffers are sufficient when you are just playing 8kHz audio files -on an empty P133 system. Using a 128k buffer just wastes 120k (or 250k) -of valuable physical RAM memory. - -The right buffer size can be easily found by making some experiments -with the dma_buffsize= parameter. I use usually 16k buffers on a DX4/100 system -and 64k on an old 386 system. - -NOTE! DMA buffers are used only by /dev/audio# and /dev/dsp# devices. - Other device files don't use them but there are two exceptions: - GUS driver uses DMA buffers when loading samples to the card. - Ensoniq SoundScape driver uses them when downloading the microcode - file (sndscape.co[012]) to the card. Using large buffers doesn't - increase performance in these cases. - -Debugging and tracing ---------------------- - -Modularized sound driver doesn't display messages during initialization as -the kernel compiled one does. This feature can be turned on by adding -trace_init=1 to the insmod command line. - -For example: - - insmod sound trace_init=1 + The following information is current as of linux-2.1.85. Check the other +readme files, especially Readme.cards, for information not specific to +making sound modular. + + First, configure your kernel. This is an idea of what you should be +setting in the sound section: + + Sound card support + + 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support + + I have SoundBlaster. Select your card from the list. + + Generic OPL2/OPL3 FM synthesizer support + FM synthesizer (YM3812/OPL-3) support + + If you don't set these, you will probably find you can play .wav files +but not .midi. As the help for them says, set them unless you know your +card does not use one of these chips for FM support. + + Once you are configured, make zlilo, modules, modules_install; reboot. +Note that it is no longer necessary or possible to configure sound in the +drivers/sound dir. Now one simply configures and makes one's kernel and +modules in the usual way. + + Then, add to your /etc/modules.conf or /etc/conf.modules something like: + +alias char-major-14 sb +post-install sb modprobe "-k" "adlib_card" +options sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330 +options adlib_card io=0x388 # FM synthetiser + + The effect of this is that the sound driver and all necessary bits and +pieces autoload on demand, assuming you use kerneld (a sound choice) and +autoclean when not in use. Also, options for the device drivers are +set. They will not work without them. Change as appropriate for your card. +If you are not yet using the very cool kerneld, you will have to "modprobe +-k sb" yourself to get things going. Eventually things may be fixed so +that this kludgery is not necessary; for the time being, it seems to work +well. + + Replace 'sb' with the driver for your card, and give it the right +options. To find the filename of the driver, look in +/lib/modules//misc. Mine looks like: + +adlib_card.o # This is the generic OPLx driver +opl3.o # The OPL3 driver +sb.o # <> +sound.o # The sound driver +uart401.o # Used by sb, maybe other cards + + Whichever card you have, try feeding it the options that would be the +default if you were making the driver wired, not as modules. You can look +at the init_module() code for the card to see what args are expected. + + Note that at present there is no way to configure the io, irq and other +parameters for the modular drivers as one does for the wired drivers.. One +needs to pass the modules the necessary parameters as arguments, either +with /etc/modules.conf or with command-line args to modprobe, e.g. + +modprobe -k sb io=0x220 irq=7 dma=1 dma16=5 mpu_io=0x330 +modprobe -k adlib_card io=0x388 + + recommend using /etc/modules.conf. + + I'm afraid I know nothing about anything but my setup, being more of a +text-mode guy anyway. If you have options for other cards or other helpful +hints, send them to me, Jim Bray, jb@as220.org, http://as220.org/jb. diff -ur --new-file old/linux/drivers/sound/ad1848.c new/linux/drivers/sound/ad1848.c --- old/linux/drivers/sound/ad1848.c Wed Jan 7 04:32:46 1998 +++ new/linux/drivers/sound/ad1848.c Thu Mar 12 19:52:09 1998 @@ -23,6 +23,12 @@ */ /* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * general sleep/wakeup clean up. + * Alan Cox : reformatted. Fixed SMP bugs. Moved to kernel alloc/free + * of irqs. Use dev_id. + * + * Status: + * Tested. Believed fully functional. */ #include @@ -144,9 +150,9 @@ static int ad_read(ad1848_info * devc, int reg) { - unsigned long flags; - int x; - int timeout = 900000; + unsigned long flags; + int x; + int timeout = 900000; while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; @@ -163,11 +169,10 @@ static void ad_write(ad1848_info * devc, int reg, int data) { - unsigned long flags; - int timeout = 900000; + unsigned long flags; + int timeout = 900000; - while (timeout > 0 && - inb(devc->base) == 0x80) /*Are we initializing */ + while (timeout > 0 && inb(devc->base) == 0x80) /* Are we initializing */ timeout--; save_flags(flags); @@ -180,7 +185,7 @@ static void wait_for_calibration(ad1848_info * devc) { - int timeout = 0; + int timeout = 0; /* * Wait until the auto calibration process has finished. @@ -1716,7 +1721,7 @@ char dev_name[100]; int e; - ad1848_info *devc = &adev_info[nr_ad1848_devs]; + ad1848_info *devc = &adev_info[nr_ad1848_devs]; ad1848_port_info *portc = NULL; @@ -1751,7 +1756,11 @@ else devc->audio_flags |= DMA_DUPLEX; } - + + portc = (ad1848_port_info *) kmalloc(sizeof(ad1848_port_info), GFP_KERNEL); + if(portc==NULL) + return -1; + if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, &ad1848_audio_driver, @@ -1762,12 +1771,11 @@ dma_playback, dma_capture)) < 0) { + kfree(portc); + portc=NULL; return -1; } - portc = (ad1848_port_info *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(ad1848_port_info))); - sound_mem_sizes[sound_nblocks] = sizeof(ad1848_port_info); - if (sound_nblocks < 1024) - sound_nblocks++;; + audio_devs[my_dev]->portc = portc; memset((char *) portc, 0, sizeof(*portc)); @@ -1777,23 +1785,21 @@ if (irq > 0) { - irq2dev[irq] = devc->dev_no = my_dev; - if (snd_set_irq_handler(devc->irq, adintr, - devc->name, - NULL) < 0) + devc->dev_no = my_dev; + if (request_irq(devc->irq, adintr, 0, devc->name, (void *)my_dev) < 0) { - printk(KERN_WARNING "ad1848: IRQ in use\n"); + printk(KERN_WARNING "ad1848: Unable to allocate IRQ\n"); } if (devc->model != MD_1848 && devc->model != MD_C930) { - int x; - unsigned char tmp = ad_read(devc, 16); + int x; + unsigned char tmp = ad_read(devc, 16); devc->timer_ticks = 0; ad_write(devc, 21, 0x00); /* Timer MSB */ ad_write(devc, 20, 0x10); /* Timer LSB */ - +#ifndef __SMP__ ad_write(devc, 16, tmp | 0x40); /* Enable timer */ for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); ad_write(devc, 16, tmp & ~0x40); /* Disable timer */ @@ -1805,6 +1811,9 @@ DDB(printk("Interrupt test OK\n")); devc->irq_ok = 1; } +#else + devc->irq_ok=1; +#endif } else devc->irq_ok = 1; /* Couldn't test. assume it's OK */ @@ -1840,7 +1849,7 @@ void ad1848_control(int cmd, int arg) { - ad1848_info *devc; + ad1848_info *devc; if (nr_ad1848_devs < 1) return; @@ -1850,7 +1859,7 @@ switch (cmd) { case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ - if (devc->model != MD_1845) + if (devc->model != MD_1845) return; ad_enter_MCE(devc); ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5)); @@ -1859,8 +1868,8 @@ case AD1848_MIXER_REROUTE: { - int o = (arg >> 8) & 0xff; - int n = arg & 0xff; + int o = (arg >> 8) & 0xff; + int n = arg & 0xff; if (n == SOUND_MIXER_NONE) { /* Just hide this control */ @@ -1906,12 +1915,14 @@ if (devc != NULL) { + if(audio_devs[dev]->portc!=NULL) + kfree(audio_devs[dev]->portc); release_region(devc->base, 4); if (!share_dma) { if (irq > 0) - snd_release_irq(devc->irq); + free_irq(devc->irq, NULL); sound_free_dma(audio_devs[dev]->dmap_out->dma); @@ -1926,35 +1937,15 @@ void adintr(int irq, void *dev_id, struct pt_regs *dummy) { - unsigned char status; - ad1848_info *devc; - int dev; - int alt_stat = 0xff; - unsigned char c930_stat = 0; - int cnt = 0; + unsigned char status; + ad1848_info *devc; + int dev; + int alt_stat = 0xff; + unsigned char c930_stat = 0; + int cnt = 0; - if (irq < 0 || irq > 15) - { - dev = -1; - } - else - dev = irq2dev[irq]; - - if (dev < 0 || dev >= num_audiodevs) - { - for (irq = 0; irq < 17; irq++) - if (irq2dev[irq] != -1) - break; - - if (irq > 15) - { - /* printk("ad1848.c: Bogus interrupt %d\n", irq); */ - return; - } - dev = irq2dev[irq]; - devc = (ad1848_info *) audio_devs[dev]->devc; - } else - devc = (ad1848_info *) audio_devs[dev]->devc; + dev = (int)dev_id; + devc = (ad1848_info *) audio_devs[dev]->devc; interrupt_again: /* Jump back here if int status doesn't reset */ @@ -2542,12 +2533,12 @@ #ifdef MODULE -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); -MODULE_PARM(dma, "i"); -MODULE_PARM(dma2, "i"); -MODULE_PARM(type, "i"); -MODULE_PARM(deskpro_xl, "i"); +MODULE_PARM(io, "i"); /* I/O for a raw AD1848 card */ +MODULE_PARM(irq, "i"); /* IRQ to use */ +MODULE_PARM(dma, "i"); /* First DMA channel */ +MODULE_PARM(dma2, "i"); /* Second DMA channel */ +MODULE_PARM(type, "i"); /* Card type */ +MODULE_PARM(deskpro_xl, "i"); /* Special magic for Deskpro XL boxen */ int io = -1; int irq = -1; diff -ur --new-file old/linux/drivers/sound/adlib_card.c new/linux/drivers/sound/adlib_card.c --- old/linux/drivers/sound/adlib_card.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/sound/adlib_card.c Wed Jan 21 01:44:57 1998 @@ -28,7 +28,6 @@ int probe_adlib(struct address_info *hw_config) { - if (check_region(hw_config->io_base, 4)) { DDB(printk("opl3.c: I/O port %x already in use\n", hw_config->io_base)); return 0; diff -ur --new-file old/linux/drivers/sound/audio.c new/linux/drivers/sound/audio.c --- old/linux/drivers/sound/audio.c Tue Dec 30 20:04:27 1997 +++ new/linux/drivers/sound/audio.c Wed Mar 11 20:39:27 1998 @@ -13,9 +13,14 @@ */ /* * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) + * Thomas Sailer : moved several static variables into struct audio_operations + * (which is grossly misnamed btw.) because they have the same + * lifetime as the rest in there and dynamic allocation saves + * 12k or so */ #include +#include #include "sound_config.h" @@ -26,51 +31,40 @@ #define NEUTRAL8 0x80 #define NEUTRAL16 0x00 -static int audio_mode[MAX_AUDIO_DEV]; -static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in nonblocking mode */ -#define AM_NONE 0 -#define AM_WRITE OPEN_WRITE -#define AM_READ OPEN_READ int dma_ioctl(int dev, unsigned int cmd, caddr_t arg); - -static int local_format[MAX_AUDIO_DEV], audio_format[MAX_AUDIO_DEV]; -static int local_conversion[MAX_AUDIO_DEV]; - -#define CNV_MU_LAW 0x00000001 - static int set_format(int dev, int fmt) { if (fmt != AFMT_QUERY) { - local_conversion[dev] = 0; + audio_devs[dev]->local_conversion = 0; if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ { if (fmt == AFMT_MU_LAW) { fmt = AFMT_U8; - local_conversion[dev] = CNV_MU_LAW; + audio_devs[dev]->local_conversion = CNV_MU_LAW; } else fmt = AFMT_U8; /* This is always supported */ } - audio_format[dev] = audio_devs[dev]->d->set_bits(dev, fmt); - local_format[dev] = fmt; + audio_devs[dev]->audio_format = audio_devs[dev]->d->set_bits(dev, fmt); + audio_devs[dev]->local_format = fmt; } else - return local_format[dev]; + return audio_devs[dev]->local_format; - return local_format[dev]; + return audio_devs[dev]->local_format; } -int audio_open(int dev, struct fileinfo *file) +int audio_open(int dev, struct file *file) { int ret; int bits; int dev_type = dev & 0x0f; - int mode = file->mode & O_ACCMODE; + int mode = translate_mode(file); dev = dev >> 4; @@ -96,15 +90,15 @@ } } - local_conversion[dev] = 0; + audio_devs[dev]->local_conversion = 0; if (dev_type == SND_DEV_AUDIO) - set_format(dev, AFMT_MU_LAW); + set_format(dev, AFMT_MU_LAW); else set_format(dev, bits); - audio_mode[dev] = AM_NONE; - dev_nblock[dev] = 0; + audio_devs[dev]->audio_mode = AM_NONE; + audio_devs[dev]->dev_nblock = 0; return ret; @@ -154,12 +148,11 @@ dmap->flags |= DMA_DIRTY; } -void audio_release(int dev, struct fileinfo *file) +void audio_release(int dev, struct file *file) { - int mode; + int mode = translate_mode(file); dev = dev >> 4; - mode = file->mode & O_ACCMODE; audio_devs[dev]->dmap_out->closing = 1; audio_devs[dev]->dmap_in->closing = 1; @@ -202,7 +195,7 @@ #endif -int audio_write(int dev, struct fileinfo *file, const char *buf, int count) +int audio_write(int dev, struct file *file, const char *buf, int count) { int c, p, l, buf_size; int err; @@ -217,9 +210,9 @@ return -EPERM; if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_mode[dev] |= AM_WRITE; + audio_devs[dev]->audio_mode |= AM_WRITE; else - audio_mode[dev] = AM_WRITE; + audio_devs[dev]->audio_mode = AM_WRITE; if (!count) /* Flush output */ { @@ -229,10 +222,10 @@ while (c) { - if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, dev_nblock[dev])) < 0) + if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, audio_devs[dev]->dev_nblock)) < 0) { /* Handle nonblocking mode */ - if (dev_nblock[dev] && err == -EAGAIN) + if (audio_devs[dev]->dev_nblock && err == -EAGAIN) return p; /* No more space. Return # of accepted bytes */ return err; } @@ -259,7 +252,7 @@ } else audio_devs[dev]->d->copy_user(dev, dma_buf, 0, buf, p, l); - if (local_conversion[dev] & CNV_MU_LAW) + if (audio_devs[dev]->local_conversion & CNV_MU_LAW) { /* * This just allows interrupts while the conversion is running @@ -276,7 +269,7 @@ return count; } -int audio_read(int dev, struct fileinfo *file, char *buf, int count) +int audio_read(int dev, struct file *file, char *buf, int count) { int c, p, l; char *dmabuf; @@ -289,24 +282,24 @@ if (!(audio_devs[dev]->open_mode & OPEN_READ)) return -EPERM; - if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) sync_output(dev); if (audio_devs[dev]->flags & DMA_DUPLEX) - audio_mode[dev] |= AM_READ; + audio_devs[dev]->audio_mode |= AM_READ; else - audio_mode[dev] = AM_READ; + audio_devs[dev]->audio_mode = AM_READ; while(c) { if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, - dev_nblock[dev])) < 0) + audio_devs[dev]->dev_nblock)) < 0) { /* * Nonblocking mode handling. Return current # of bytes */ - if (dev_nblock[dev] && buf_no == -EAGAIN) + if (audio_devs[dev]->dev_nblock && buf_no == -EAGAIN) return p; if (p > 0) /* Avoid throwing away data */ @@ -321,7 +314,7 @@ * Insert any local processing here. */ - if (local_conversion[dev] & CNV_MU_LAW) + if (audio_devs[dev]->local_conversion & CNV_MU_LAW) { /* * This just allows interrupts while the conversion is running @@ -347,159 +340,165 @@ return count - c; } -int audio_ioctl(int dev, struct fileinfo *file_must_not_be_used, - unsigned int cmd, caddr_t arg) +int audio_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) { - int val, info, count; + int val, count; unsigned long flags; struct dma_buffparms *dmap; dev = dev >> 4; - if (((cmd >> 8) & 0xff) == 'C') { + if (_IOC_TYPE(cmd) == 'C') { if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0); /* else printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */ return -ENXIO; - } else switch (cmd) { - case SNDCTL_DSP_SYNC: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - if (audio_devs[dev]->dmap_out->fragment_size == 0) + } + else switch (cmd) + { + case SNDCTL_DSP_SYNC: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + if (audio_devs[dev]->dmap_out->fragment_size == 0) + return 0; + sync_output(dev); + DMAbuf_sync(dev); + DMAbuf_reset(dev); return 0; - sync_output(dev); - DMAbuf_sync(dev); - DMAbuf_reset(dev); - return 0; - case SNDCTL_DSP_POST: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + case SNDCTL_DSP_POST: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + if (audio_devs[dev]->dmap_out->fragment_size == 0) + return 0; + audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; + sync_output(dev); + dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0); return 0; - if (audio_devs[dev]->dmap_out->fragment_size == 0) + + case SNDCTL_DSP_RESET: + audio_devs[dev]->audio_mode = AM_NONE; + DMAbuf_reset(dev); return 0; - audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; - sync_output(dev); - dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0); - return 0; - case SNDCTL_DSP_RESET: - audio_mode[dev] = AM_NONE; - DMAbuf_reset(dev); - return 0; - - case SNDCTL_DSP_GETFMTS: - val = audio_devs[dev]->format_mask; - return __put_user(val, (int *)arg); - - case SNDCTL_DSP_SETFMT: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = set_format(dev, val); - return __put_user(val, (int *)arg); + case SNDCTL_DSP_GETFMTS: + val = audio_devs[dev]->format_mask; + break; + + case SNDCTL_DSP_SETFMT: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = set_format(dev, val); + break; - case SNDCTL_DSP_GETISPACE: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; - return dma_ioctl(dev, cmd, arg); - - case SNDCTL_DSP_GETOSPACE: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EPERM; - if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; - return dma_ioctl(dev, cmd, arg); + case SNDCTL_DSP_GETISPACE: + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return 0; + if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + return -EBUSY; + return dma_ioctl(dev, cmd, arg); + + case SNDCTL_DSP_GETOSPACE: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EPERM; + if ((audio_devs[dev]->audio_mode & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) + return -EBUSY; + return dma_ioctl(dev, cmd, arg); - case SNDCTL_DSP_NONBLOCK: - dev_nblock[dev] = 1; - return 0; - - case SNDCTL_DSP_GETCAPS: - info = 1 | DSP_CAP_MMAP; /* Revision level of this ioctl() */ - if (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode == OPEN_READWRITE) - info |= DSP_CAP_DUPLEX; - if (audio_devs[dev]->coproc) - info |= DSP_CAP_COPROC; - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - info |= DSP_CAP_BATCH; - if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ - info |= DSP_CAP_TRIGGER; - return __put_user(info, (int *)arg); + case SNDCTL_DSP_NONBLOCK: + audio_devs[dev]->dev_nblock = 1; + return 0; + + case SNDCTL_DSP_GETCAPS: + val = 1 | DSP_CAP_MMAP; /* Revision level of this ioctl() */ + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode == OPEN_READWRITE) + val |= DSP_CAP_DUPLEX; + if (audio_devs[dev]->coproc) + val |= DSP_CAP_COPROC; + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ + val |= DSP_CAP_BATCH; + if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ + val |= DSP_CAP_TRIGGER; + break; - case SOUND_PCM_WRITE_RATE: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = audio_devs[dev]->d->set_speed(dev, val); - return __put_user(val, (int *)arg); - - case SOUND_PCM_READ_RATE: - val = audio_devs[dev]->d->set_speed(dev, 0); - return __put_user(val, (int *)arg); - - case SNDCTL_DSP_STEREO: - if (__get_user(val, (int *)arg)) - return -EFAULT; - if (val > 1 || val < 0) - return -EINVAL; - val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1; - return __put_user(val, (int *)arg); - - case SOUND_PCM_WRITE_CHANNELS: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = audio_devs[dev]->d->set_channels(dev, val); - return __put_user(val, (int *)arg); - - case SOUND_PCM_READ_CHANNELS: - val = audio_devs[dev]->d->set_channels(dev, 0); - return __put_user(val, (int *)arg); + case SOUND_PCM_WRITE_RATE: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = audio_devs[dev]->d->set_speed(dev, val); + break; + + case SOUND_PCM_READ_RATE: + val = audio_devs[dev]->d->set_speed(dev, 0); + break; + + case SNDCTL_DSP_STEREO: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val > 1 || val < 0) + return -EINVAL; + val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1; + break; + + case SOUND_PCM_WRITE_CHANNELS: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = audio_devs[dev]->d->set_channels(dev, val); + break; + + case SOUND_PCM_READ_CHANNELS: + val = audio_devs[dev]->d->set_channels(dev, 0); + break; - case SOUND_PCM_READ_BITS: - val = audio_devs[dev]->d->set_bits(dev, 0); - return __put_user(val, (int *)arg); - - case SNDCTL_DSP_SETDUPLEX: - if (audio_devs[dev]->open_mode != OPEN_READWRITE) - return -EPERM; - return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO; - - case SNDCTL_DSP_PROFILE: - if (__get_user(val, (int *)arg)) - return -EFAULT; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->applic_profile = val; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->applic_profile = val; - return 0; + case SOUND_PCM_READ_BITS: + val = audio_devs[dev]->d->set_bits(dev, 0); + break; + + case SNDCTL_DSP_SETDUPLEX: + if (audio_devs[dev]->open_mode != OPEN_READWRITE) + return -EPERM; + return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO; + + case SNDCTL_DSP_PROFILE: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (audio_devs[dev]->open_mode & OPEN_WRITE) + audio_devs[dev]->dmap_out->applic_profile = val; + if (audio_devs[dev]->open_mode & OPEN_READ) + audio_devs[dev]->dmap_in->applic_profile = val; + return 0; - case SNDCTL_DSP_GETODELAY: - dmap = audio_devs[dev]->dmap_out; - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - if (!(dmap->flags & DMA_ALLOC_DONE)) - return __put_user(0, (int *)arg); + case SNDCTL_DSP_GETODELAY: + dmap = audio_devs[dev]->dmap_out; + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + if (!(dmap->flags & DMA_ALLOC_DONE)) + { + val=0; + break; + } - save_flags (flags); - cli(); - /* Compute number of bytes that have been played */ - count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); - if (count < dmap->fragment_size && dmap->qhead != 0) - count += dmap->bytes_in_use; /* Pointer wrap not handled yet */ - count += dmap->byte_counter; + save_flags (flags); + cli(); + /* Compute number of bytes that have been played */ + count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); + if (count < dmap->fragment_size && dmap->qhead != 0) + count += dmap->bytes_in_use; /* Pointer wrap not handled yet */ + count += dmap->byte_counter; - /* Substract current count from the number of bytes written by app */ - count = dmap->user_counter - count; - if (count < 0) - count = 0; - restore_flags (flags); - return __put_user(count, (int *)arg); + /* Substract current count from the number of bytes written by app */ + count = dmap->user_counter - count; + if (count < 0) + count = 0; + restore_flags (flags); + val = count; + break; - default: - return dma_ioctl(dev, cmd, arg); + default: + return dma_ioctl(dev, cmd, arg); } + return put_user(val, (int *)arg); } void audio_init_devices(void) @@ -641,7 +640,8 @@ static int dma_subdivide(int dev, struct dma_buffparms *dmap, int fact) { - if (fact == 0) { + if (fact == 0) + { fact = dmap->subdivision; if (fact == 0) fact = 1; @@ -722,210 +722,228 @@ int fact, ret, changed, bits, count, err; unsigned long flags; - switch (cmd) { - case SNDCTL_DSP_SUBDIVIDE: - ret = 0; - if (__get_user(fact, (int *)arg)) - return -EFAULT; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - ret = dma_subdivide(dev, dmap_out, fact); - if (ret < 0) - return ret; - if (audio_devs[dev]->open_mode != OPEN_WRITE || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - ret = dma_subdivide(dev, dmap_in, fact); - if (ret < 0) - return ret; - return __put_user(ret, (int *)arg); - - case SNDCTL_DSP_GETISPACE: - case SNDCTL_DSP_GETOSPACE: - dmap = dmap_out; - if (cmd == SNDCTL_DSP_GETISPACE && !(audio_devs[dev]->open_mode & OPEN_READ)) - return -EINVAL; - if (cmd == SNDCTL_DSP_GETOSPACE && !(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) - dmap = dmap_in; - if (dmap->mapping_flags & DMA_MAP_MAPPED) - return -EINVAL; - if (!(dmap->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); - info.fragstotal = dmap->nbufs; - if (cmd == SNDCTL_DSP_GETISPACE) - info.fragments = dmap->qlen; - else { - if (!DMAbuf_space_in_queue(dev)) - info.fragments = 0; - else { - info.fragments = DMAbuf_space_in_queue(dev); - if (audio_devs[dev]->d->local_qlen) { - int tmp = audio_devs[dev]->d->local_qlen(dev); - if (tmp && info.fragments) - tmp--; /* - * This buffer has been counted twice - */ - info.fragments -= tmp; + switch (cmd) + { + case SNDCTL_DSP_SUBDIVIDE: + ret = 0; + if (get_user(fact, (int *)arg)) + return -EFAULT; + if (audio_devs[dev]->open_mode & OPEN_WRITE) + ret = dma_subdivide(dev, dmap_out, fact); + if (ret < 0) + return ret; + if (audio_devs[dev]->open_mode != OPEN_WRITE || + (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ)) + ret = dma_subdivide(dev, dmap_in, fact); + if (ret < 0) + return ret; + break; + + case SNDCTL_DSP_GETISPACE: + case SNDCTL_DSP_GETOSPACE: + dmap = dmap_out; + if (cmd == SNDCTL_DSP_GETISPACE && !(audio_devs[dev]->open_mode & OPEN_READ)) + return -EINVAL; + if (cmd == SNDCTL_DSP_GETOSPACE && !(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) + dmap = dmap_in; + if (dmap->mapping_flags & DMA_MAP_MAPPED) + return -EINVAL; + if (!(dmap->flags & DMA_ALLOC_DONE)) + reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); + info.fragstotal = dmap->nbufs; + if (cmd == SNDCTL_DSP_GETISPACE) + info.fragments = dmap->qlen; + else + { + if (!DMAbuf_space_in_queue(dev)) + info.fragments = 0; + else + { + info.fragments = DMAbuf_space_in_queue(dev); + if (audio_devs[dev]->d->local_qlen) + { + int tmp = audio_devs[dev]->d->local_qlen(dev); + if (tmp && info.fragments) + tmp--; /* + * This buffer has been counted twice + */ + info.fragments -= tmp; + } } } - } - if (info.fragments < 0) + if (info.fragments < 0) info.fragments = 0; - else if (info.fragments > dmap->nbufs) - info.fragments = dmap->nbufs; + else if (info.fragments > dmap->nbufs) + info.fragments = dmap->nbufs; - info.fragsize = dmap->fragment_size; - info.bytes = info.fragments * dmap->fragment_size; + info.fragsize = dmap->fragment_size; + info.bytes = info.fragments * dmap->fragment_size; - if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) - info.bytes -= dmap->counts[dmap->qhead]; - else { - info.fragments = info.bytes / dmap->fragment_size; - info.bytes -= dmap->user_counter % dmap->fragment_size; - } - return __copy_to_user(arg, &info, sizeof(info)); + if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) + info.bytes -= dmap->counts[dmap->qhead]; + else + { + info.fragments = info.bytes / dmap->fragment_size; + info.bytes -= dmap->user_counter % dmap->fragment_size; + } + if (copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + return 0; - case SNDCTL_DSP_SETTRIGGER: - if (__get_user(bits, (int *)arg)) - return -EFAULT; - bits &= audio_devs[dev]->open_mode; - if (audio_devs[dev]->d->trigger == NULL) - return -EINVAL; - if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) && - (bits & PCM_ENABLE_OUTPUT)) - return -EINVAL; - save_flags(flags); - cli(); - changed = audio_devs[dev]->enable_bits ^ bits; - if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) { - reorganize_buffers(dev, dmap_in, 1); - if ((err = audio_devs[dev]->d->prepare_for_input(dev, + case SNDCTL_DSP_SETTRIGGER: + if (get_user(bits, (int *)arg)) + return -EFAULT; + bits &= audio_devs[dev]->open_mode; + if (audio_devs[dev]->d->trigger == NULL) + return -EINVAL; + if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) && + (bits & PCM_ENABLE_OUTPUT)) + return -EINVAL; + save_flags(flags); + cli(); + changed = audio_devs[dev]->enable_bits ^ bits; + if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) + { + reorganize_buffers(dev, dmap_in, 1); + if ((err = audio_devs[dev]->d->prepare_for_input(dev, dmap_in->fragment_size, dmap_in->nbufs)) < 0) - return -err; - dmap_in->dma_mode = DMODE_INPUT; + return -err; + dmap_in->dma_mode = DMODE_INPUT; + audio_devs[dev]->enable_bits = bits; + DMAbuf_activate_recording(dev, dmap_in); + } + if ((changed & bits) & PCM_ENABLE_OUTPUT && + (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && + audio_devs[dev]->go) + { + if (!(dmap_out->flags & DMA_ALLOC_DONE)) + reorganize_buffers(dev, dmap_out, 0); + dmap_out->dma_mode = DMODE_OUTPUT; + audio_devs[dev]->enable_bits = bits; + dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; + DMAbuf_launch_output(dev, dmap_out); + } audio_devs[dev]->enable_bits = bits; - DMAbuf_activate_recording(dev, dmap_in); - } - if ((changed & bits) & PCM_ENABLE_OUTPUT && - (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && - audio_devs[dev]->go) { + if (changed && audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); + restore_flags(flags); + /* Falls through... */ + + case SNDCTL_DSP_GETTRIGGER: + ret = audio_devs[dev]->enable_bits; + break; + + case SNDCTL_DSP_SETSYNCRO: + if (!audio_devs[dev]->d->trigger) + return -EINVAL; + audio_devs[dev]->d->trigger(dev, 0); + audio_devs[dev]->go = 0; + return 0; + + case SNDCTL_DSP_GETIPTR: + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -EINVAL; + save_flags(flags); + cli(); + cinfo.bytes = dmap_in->byte_counter; + cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3; + if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0) + cinfo.bytes += dmap_in->bytes_in_use; /* Pointer wrap not handled yet */ + cinfo.blocks = dmap_in->qlen; + cinfo.bytes += cinfo.ptr; + if (dmap_in->mapping_flags & DMA_MAP_MAPPED) + dmap_in->qlen = 0; /* Reset interrupt counter */ + restore_flags(flags); + if (copy_to_user(arg, &cinfo, sizeof(cinfo))) + return -EFAULT; + return 0; + + case SNDCTL_DSP_GETOPTR: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; + + save_flags(flags); + cli(); + cinfo.bytes = dmap_out->byte_counter; + cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3; + if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0) + cinfo.bytes += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ + cinfo.blocks = dmap_out->qlen; + cinfo.bytes += cinfo.ptr; + if (dmap_out->mapping_flags & DMA_MAP_MAPPED) + dmap_out->qlen = 0; /* Reset interrupt counter */ + restore_flags(flags); + if (copy_to_user(arg, &cinfo, sizeof(cinfo))) + return -EFAULT; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -EINVAL; if (!(dmap_out->flags & DMA_ALLOC_DONE)) - reorganize_buffers(dev, dmap_out, 0); - dmap_out->dma_mode = DMODE_OUTPUT; - audio_devs[dev]->enable_bits = bits; - dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; - DMAbuf_launch_output(dev, dmap_out); - } - audio_devs[dev]->enable_bits = bits; - if (changed && audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); - restore_flags(flags); - /* Falls through... */ - - case SNDCTL_DSP_GETTRIGGER: - ret = audio_devs[dev]->enable_bits; - return __put_user(ret, (int *)arg); - - case SNDCTL_DSP_SETSYNCRO: - if (!audio_devs[dev]->d->trigger) - return -EINVAL; - audio_devs[dev]->d->trigger(dev, 0); - audio_devs[dev]->go = 0; - return 0; - - case SNDCTL_DSP_GETIPTR: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EINVAL; - save_flags(flags); - cli(); - cinfo.bytes = dmap_in->byte_counter; - cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3; - if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0) - cinfo.bytes += dmap_in->bytes_in_use; /* Pointer wrap not handled yet */ - cinfo.blocks = dmap_in->qlen; - cinfo.bytes += cinfo.ptr; - if (dmap_in->mapping_flags & DMA_MAP_MAPPED) - dmap_in->qlen = 0; /* Reset interrupt counter */ - restore_flags(flags); - return __copy_to_user(arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETOPTR: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - - save_flags(flags); - cli(); - cinfo.bytes = dmap_out->byte_counter; - cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3; - if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0) - cinfo.bytes += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ - cinfo.blocks = dmap_out->qlen; - cinfo.bytes += cinfo.ptr; - if (dmap_out->mapping_flags & DMA_MAP_MAPPED) - dmap_out->qlen = 0; /* Reset interrupt counter */ - restore_flags(flags); - return __copy_to_user(arg, &cinfo, sizeof(cinfo)); - - case SNDCTL_DSP_GETODELAY: - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return -EINVAL; - if (!(dmap_out->flags & DMA_ALLOC_DONE)) - return __put_user(0, (int *)arg); - save_flags(flags); - cli(); - /* Compute number of bytes that have been played */ - count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT); - if (count < dmap_out->fragment_size && dmap_out->qhead != 0) - count += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ - count += dmap_out->byte_counter; - /* Substract current count from the number of bytes written by app */ - count = dmap_out->user_counter - count; - if (count < 0) - count = 0; - restore_flags (flags); - return __put_user(count, (int *)arg); - - case SNDCTL_DSP_POST: - if (audio_devs[dev]->dmap_out->qlen > 0) - if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) - DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out); - return 0; - - case SNDCTL_DSP_GETBLKSIZE: - dmap = dmap_out; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - reorganize_buffers(dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - reorganize_buffers(dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->open_mode == OPEN_READ) - dmap = dmap_in; - ret = dmap->fragment_size; - return __put_user(ret, (int *)arg); - - case SNDCTL_DSP_SETFRAGMENT: - ret = 0; - if (__get_user(fact, (int *)arg)) - return -EFAULT; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - ret = dma_set_fragment(dev, dmap_out, fact); - if (ret < 0) - return ret; - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->flags & DMA_DUPLEX && - audio_devs[dev]->open_mode & OPEN_READ)) - ret = dma_set_fragment(dev, dmap_in, fact); - if (ret < 0) - return ret; - if (!arg) /* don't know what this is good for, but preserve old semantics */ + { + ret=0; + break; + } + save_flags(flags); + cli(); + /* Compute number of bytes that have been played */ + count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT); + if (count < dmap_out->fragment_size && dmap_out->qhead != 0) + count += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ + count += dmap_out->byte_counter; + /* Substract current count from the number of bytes written by app */ + count = dmap_out->user_counter - count; + if (count < 0) + count = 0; + restore_flags (flags); + ret = count; + break; + + case SNDCTL_DSP_POST: + if (audio_devs[dev]->dmap_out->qlen > 0) + if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) + DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out); return 0; - return __put_user(ret, (int *)arg); - default: - if (!audio_devs[dev]->d->ioctl) - return -EINVAL; - return audio_devs[dev]->d->ioctl(dev, cmd, arg); + case SNDCTL_DSP_GETBLKSIZE: + dmap = dmap_out; + if (audio_devs[dev]->open_mode & OPEN_WRITE) + reorganize_buffers(dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->open_mode == OPEN_READ || + (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ)) + reorganize_buffers(dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ)); + if (audio_devs[dev]->open_mode == OPEN_READ) + dmap = dmap_in; + ret = dmap->fragment_size; + break; + + case SNDCTL_DSP_SETFRAGMENT: + ret = 0; + if (get_user(fact, (int *)arg)) + return -EFAULT; + if (audio_devs[dev]->open_mode & OPEN_WRITE) + ret = dma_set_fragment(dev, dmap_out, fact); + if (ret < 0) + return ret; + if (audio_devs[dev]->open_mode == OPEN_READ || + (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ)) + ret = dma_set_fragment(dev, dmap_in, fact); + if (ret < 0) + return ret; + if (!arg) /* don't know what this is good for, but preserve old semantics */ + return 0; + break; + + default: + if (!audio_devs[dev]->d->ioctl) + return -EINVAL; + return audio_devs[dev]->d->ioctl(dev, cmd, arg); } + return put_user(ret, (int *)arg); } diff -ur --new-file old/linux/drivers/sound/bin2hex.c new/linux/drivers/sound/bin2hex.c --- old/linux/drivers/sound/bin2hex.c Tue Dec 23 22:52:02 1997 +++ new/linux/drivers/sound/bin2hex.c Thu Mar 12 19:52:09 1998 @@ -2,12 +2,27 @@ int main( int argc, const char * argv [] ) { - const char * varname = argv[1]; + const char * varname; int i = 0; int c; + int id = 0; + if(argv[1] && strcmp(argv[1],"-i")==0) + { + argv++; + argc--; + id=1; + } + + if(argc==1) + { + fprintf(stderr, "bin2hex: [-i] firmware\n"); + exit(1); + } + + varname = argv[1]; printf( "/* automatically generated by bin2hex */\n" ); - printf( "static unsigned char %s [] =\n{\n", varname ); + printf( "static unsigned char %s [] %s =\n{\n", varname , id?"__initdata":""); while ( ( c = getchar( ) ) != EOF ) { diff -ur --new-file old/linux/drivers/sound/cs4232.c new/linux/drivers/sound/cs4232.c --- old/linux/drivers/sound/cs4232.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/sound/cs4232.c Thu Mar 12 19:52:09 1998 @@ -12,7 +12,14 @@ * CS4232 * CS4236 * CS4236B + * + * Note: You will need a PnP config setup to initialise some CS4232 boards + * anyway. + * + * Changes + * Alan Cox Modularisation, Basic cleanups. */ + /* * Copyright (C) by Hannu Savolainen 1993-1997 * @@ -20,6 +27,7 @@ * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ + #include #include @@ -31,23 +39,22 @@ #define KEY_PORT 0x279 /* Same as LPT1 status port */ #define CSN_NUM 0x99 /* Just a random number */ -static void -CS_OUT(unsigned char a) +static void CS_OUT(unsigned char a) { - outb((a), KEY_PORT); + outb(a, KEY_PORT); } + #define CS_OUT2(a, b) {CS_OUT(a);CS_OUT(b);} #define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);} -static int mpu_base = 0, mpu_irq = 0; -static int mpu_detected = 0; +static int mpu_base = 0, mpu_irq = 0; +static int mpu_detected = 0; -int -probe_cs4232_mpu(struct address_info *hw_config) +int probe_cs4232_mpu(struct address_info *hw_config) { -/* - * Just write down the config values. - */ + /* + * Just write down the config values. + */ mpu_base = hw_config->io_base; mpu_irq = hw_config->irq; @@ -55,9 +62,9 @@ return 1; } -void -attach_cs4232_mpu(struct address_info *hw_config) +void attach_cs4232_mpu(struct address_info *hw_config) { + /* Nothing needs doing */ } static unsigned char crystal_key[] = /* A 32 byte magic key sequence */ @@ -68,190 +75,128 @@ 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a }; -int -probe_cs4232(struct address_info *hw_config) +static void sleep(unsigned howlong) { - int i, n; - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - - static struct wait_queue *cs_sleeper = NULL; - static volatile struct snd_wait cs_sleep_flag = - {0}; - + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + howlong; + schedule(); + current->timeout = 0; +} -/* - * Verify that the I/O port range is free. - */ +int probe_cs4232(struct address_info *hw_config) +{ + int i, n; + int base = hw_config->io_base, irq = hw_config->irq; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; + + /* + * Verify that the I/O port range is free. + */ if (check_region(base, 4)) - { - printk("cs4232.c: I/O port 0x%03x not free\n", base); - return 0; - } + { + printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base); + return 0; + } if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) return 1; /* The card is already active */ -/* - * This version of the driver doesn't use the PnP method when configuring - * the card but a simplified method defined by Crystal. This means that - * just one CS4232 compatible device can exist on the system. Also this - * method conflicts with possible PnP support in the OS. For this reason - * driver is just a temporary kludge. - */ - -/* - * Repeat initialization few times since it doesn't always succeed in - * first time. - */ + /* + * This version of the driver doesn't use the PnP method when configuring + * the card but a simplified method defined by Crystal. This means that + * just one CS4232 compatible device can exist on the system. Also this + * method conflicts with possible PnP support in the OS. For this reason + * driver is just a temporary kludge. + * + * Also the Cirrus/Crystal method doesnt always work. Try ISAPnP first ;) + */ + + /* + * Repeat initialization few times since it doesn't always succeed in + * first time. + */ for (n = 0; n < 4; n++) - { - cs_sleep_flag.opts = WK_NONE; -/* - * Wake up the card by sending a 32 byte Crystal key to the key port. - */ - for (i = 0; i < 32; i++) - CS_OUT(crystal_key[i]); - - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Delay */ - -/* - * Now set the CSN (Card Select Number). - */ - - CS_OUT2(0x06, CSN_NUM); - - -/* - * Then set some config bytes. First logical device 0 - */ - - CS_OUT2(0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */ - CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */ - - if (check_region(0x388, 4)) /* Not free */ - CS_OUT3(0x48, 0x00, 0x00) /* FM base off */ - else - CS_OUT3(0x48, 0x03, 0x88); /* FM base 0x388 */ - - CS_OUT3(0x42, 0x00, 0x00); /* SB base off */ - CS_OUT2(0x22, irq); /* SB+WSS IRQ */ - CS_OUT2(0x2a, dma1); /* SB+WSS DMA */ - - if (dma2 != -1) - CS_OUT2(0x25, dma2) /* WSS DMA2 */ - else - CS_OUT2(0x25, 4); /* No WSS DMA2 */ - - CS_OUT2(0x33, 0x01); /* Activate logical dev 0 */ - - - { - unsigned long tlimit; - - if (HZ / 10) - current->timeout = tlimit = jiffies + (HZ / 10); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Delay */ - -/* - * Initialize logical device 3 (MPU) - */ + { + /* + * Wake up the card by sending a 32 byte Crystal key to the key port. + */ + + for (i = 0; i < 32; i++) + CS_OUT(crystal_key[i]); + + sleep(HZ / 10); + + /* + * Now set the CSN (Card Select Number). + */ + + CS_OUT2(0x06, CSN_NUM); + + /* + * Then set some config bytes. First logical device 0 + */ + + CS_OUT2(0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */ + CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */ + + if (check_region(0x388, 4)) /* Not free */ + CS_OUT3(0x48, 0x00, 0x00) /* FM base off */ + else + CS_OUT3(0x48, 0x03, 0x88); /* FM base 0x388 */ + + CS_OUT3(0x42, 0x00, 0x00); /* SB base off */ + CS_OUT2(0x22, irq); /* SB+WSS IRQ */ + CS_OUT2(0x2a, dma1); /* SB+WSS DMA */ + + if (dma2 != -1) + CS_OUT2(0x25, dma2) /* WSS DMA2 */ + else + CS_OUT2(0x25, 4); /* No WSS DMA2 */ + + CS_OUT2(0x33, 0x01); /* Activate logical dev 0 */ + + sleep(HZ / 10); + + /* + * Initialize logical device 3 (MPU) + */ #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) - if (mpu_base != 0 && mpu_irq != 0) - { - CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */ - CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */ - CS_OUT2(0x22, mpu_irq); /* MPU IRQ */ - CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */ - } + if (mpu_base != 0 && mpu_irq != 0) + { + CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */ + CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */ + CS_OUT2(0x22, mpu_irq); /* MPU IRQ */ + CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */ + } #endif -/* - * Finally activate the chip - */ - CS_OUT(0x79); - - - { - unsigned long tlimit; - - if (HZ / 5) - current->timeout = tlimit = jiffies + (HZ / 5); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Delay */ - -/* - * Then try to detect the codec part of the chip - */ - - if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) - return 1; - - - { - unsigned long tlimit; - - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - cs_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&cs_sleeper); - if (!(cs_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - cs_sleep_flag.opts |= WK_TIMEOUT; - } - cs_sleep_flag.opts &= ~WK_SLEEP; - }; /* Longer delay */ - } - + /* + * Finally activate the chip + */ + + CS_OUT(0x79); + + sleep(HZ / 5); + + /* + * Then try to detect the codec part of the chip + */ + + if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp)) + return 1; + + sleep(HZ); + } return 0; } -void -attach_cs4232(struct address_info *hw_config) +void attach_cs4232(struct address_info *hw_config) { - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - int old_num_mixers = num_mixers; + int base = hw_config->io_base, irq = hw_config->irq; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; + int old_num_mixers = num_mixers; if (dma2 == -1) dma2 = dma1; @@ -264,45 +209,47 @@ hw_config->osp); if (num_mixers > old_num_mixers) - { /* Assume the mixer map is as suggested in the CS4232 databook */ - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */ - } + { + /* Assume the mixer map is as suggested in the CS4232 databook */ + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */ + } #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0) - { - static struct address_info hw_config2 = - {0}; /* Ensure it's initialized */ - - hw_config2.io_base = mpu_base; - hw_config2.irq = mpu_irq; - hw_config2.dma = -1; - hw_config2.dma2 = -1; - hw_config2.always_detect = 0; - hw_config2.name = NULL; - hw_config2.driver_use_1 = 0; - hw_config2.driver_use_2 = 0; - hw_config2.card_subtype = 0; - - if (probe_uart401(&hw_config2)) - { - mpu_detected = 1; - attach_uart401(&hw_config2); - } else - { - mpu_base = mpu_irq = 0; - } - hw_config->slots[1] = hw_config2.slots[1]; - } + { + static struct address_info hw_config2 = { + 0 + }; /* Ensure it's initialized */ + + hw_config2.io_base = mpu_base; + hw_config2.irq = mpu_irq; + hw_config2.dma = -1; + hw_config2.dma2 = -1; + hw_config2.always_detect = 0; + hw_config2.name = NULL; + hw_config2.driver_use_1 = 0; + hw_config2.driver_use_2 = 0; + hw_config2.card_subtype = 0; + + if (probe_uart401(&hw_config2)) + { + mpu_detected = 1; + attach_uart401(&hw_config2); + } + else + { + mpu_base = mpu_irq = 0; + } + hw_config->slots[1] = hw_config2.slots[1]; + } #endif } -void -unload_cs4232(struct address_info *hw_config) +void unload_cs4232(struct address_info *hw_config) { - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; + int base = hw_config->io_base, irq = hw_config->irq; + int dma1 = hw_config->dma, dma2 = hw_config->dma2; if (dma2 == -1) dma2 = dma1; @@ -315,28 +262,29 @@ sound_unload_audiodev(hw_config->slots[0]); #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (mpu_base != 0 && mpu_irq != 0 && mpu_detected) - { - static struct address_info hw_config2 = - {0}; /* Ensure it's initialized */ - - hw_config2.io_base = mpu_base; - hw_config2.irq = mpu_irq; - hw_config2.dma = -1; - hw_config2.dma2 = -1; - hw_config2.always_detect = 0; - hw_config2.name = NULL; - hw_config2.driver_use_1 = 0; - hw_config2.driver_use_2 = 0; - hw_config2.card_subtype = 0; - hw_config2.slots[1] = hw_config->slots[1]; + { + static struct address_info hw_config2 = + { + 0 + }; /* Ensure it's initialized */ + + hw_config2.io_base = mpu_base; + hw_config2.irq = mpu_irq; + hw_config2.dma = -1; + hw_config2.dma2 = -1; + hw_config2.always_detect = 0; + hw_config2.name = NULL; + hw_config2.driver_use_1 = 0; + hw_config2.driver_use_2 = 0; + hw_config2.card_subtype = 0; + hw_config2.slots[1] = hw_config->slots[1]; - unload_uart401(&hw_config2); - } + unload_uart401(&hw_config2); + } #endif } -void -unload_cs4232_mpu(struct address_info *hw_config) +void unload_cs4232_mpu(struct address_info *hw_config) { /* Not required. Handled by cs4232_unload */ } @@ -348,21 +296,25 @@ int dma = -1; int dma2 = -1; +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(dma2,"i"); + struct address_info cfg; /* - * Install a CS4232 based card. Need to have ad1848 and mpu401 - * loaded ready. + * Install a CS4232 based card. Need to have ad1848 and mpu401 + * loaded ready. */ -int -init_module(void) +int init_module(void) { if (io == -1 || irq == -1 || dma == -1 || dma2 == -1) - { - printk(KERN_ERR "cs4232: dma, dma2, irq and io must be set.\n"); - return -EINVAL; - } + { + printk(KERN_ERR "cs4232: dma, dma2, irq and io must be set.\n"); + return -EINVAL; + } cfg.io_base = io; cfg.irq = irq; cfg.dma = dma; @@ -379,13 +331,12 @@ return 0; } -void -cleanup_module(void) +void cleanup_module(void) { unload_cs4232_mpu(&cfg); unload_cs4232(&cfg); SOUND_LOCK_END; } -#endif +#endif #endif 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 Sun Jan 4 19:40:16 1998 +++ new/linux/drivers/sound/dev_table.c Tue Mar 10 20:01:47 1998 @@ -3,6 +3,7 @@ * * Device call tables. */ + /* * Copyright (C) by Hannu Savolainen 1993-1997 * @@ -10,22 +11,21 @@ * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ + #include #define _DEV_TABLE_C_ #include "sound_config.h" -int sb_be_quiet = 0; -int softoss_dev = 0; - -int sound_started = 0; -int sndtable_get_cardcount(void); +int sb_be_quiet = 0; +int softoss_dev = 0; +int sound_started = 0; +int sndtable_get_cardcount(void); -int -snd_find_driver(int type) +int snd_find_driver(int type) { - int i, n = num_sound_drivers; + int i, n = num_sound_drivers; for (i = 0; i < n; i++) if (sound_drivers[i].card_type == type) @@ -34,25 +34,23 @@ return -1; } -static void -start_services(void) +static void start_services(void) { - int soundcards_installed; - #ifdef FIXME + int soundcards_installed; + if (!(soundcards_installed = sndtable_get_cardcount())) return; /* No cards detected */ #endif #ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ - { - int dev; - - for (dev = 0; dev < num_audiodevs; dev++) - { - } - audio_init_devices(); + { + int dev; + for (dev = 0; dev < num_audiodevs; dev++) + { + } + audio_init_devices(); } #endif @@ -62,17 +60,16 @@ static void start_cards(void) { - int i, n = num_sound_cards; - int drv; + int i, n = num_sound_cards; + int drv; sound_started = 1; if (trace_init) - printk("Sound initialization started\n"); + printk(KERN_DEBUG "Sound initialization started\n"); #ifdef CONFIG_LOWLEVEL_SOUND { - extern void sound_preinit_lowlevel_drivers(void); - + extern void sound_preinit_lowlevel_drivers(void); sound_preinit_lowlevel_drivers(); } #endif @@ -85,251 +82,241 @@ num_sound_cards = i + 1; for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + { if (snd_installed_cards[i].enabled) - { - snd_installed_cards[i].for_driver_use = NULL; - - if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) - { - snd_installed_cards[i].enabled = 0; /* - * Mark as not detected - */ - continue; - } - snd_installed_cards[i].config.card_subtype = - sound_drivers[drv].card_subtype; - - if (sound_drivers[drv].probe(&snd_installed_cards[i].config)) - { + { + snd_installed_cards[i].for_driver_use = NULL; - sound_drivers[drv].attach(&snd_installed_cards[i].config); - - } else - snd_installed_cards[i].enabled = 0; /* + if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) + { + snd_installed_cards[i].enabled = 0; /* + * Mark as not detected + */ + continue; + } + snd_installed_cards[i].config.card_subtype = + sound_drivers[drv].card_subtype; + + if (sound_drivers[drv].probe(&snd_installed_cards[i].config)) + sound_drivers[drv].attach(&snd_installed_cards[i].config); + else + snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ - } + } + } #ifdef CONFIG_LOWLEVEL_SOUND { extern void sound_init_lowlevel_drivers(void); - sound_init_lowlevel_drivers(); } #endif - if (trace_init) - printk("Sound initialization complete\n"); + printk(KERN_DEBUG "Sound initialization complete\n"); } -void -sndtable_init(void) +void sndtable_init(void) { start_cards(); } -void -sound_unload_drivers(void) +void sound_unload_drivers(void) { - int i, n = num_sound_cards; - int drv; + int i, n = num_sound_cards; + int drv; if (!sound_started) return; if (trace_init) - printk("Sound unload started\n"); + printk(KERN_DEBUG "Sound unload started\n"); for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + { if (snd_installed_cards[i].enabled) - { - if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1) - { - if (sound_drivers[drv].unload) - { - sound_drivers[drv].unload(&snd_installed_cards[i].config); - snd_installed_cards[i].enabled = 0; - } - } - } - for (i=0;iio_base; - snd_installed_cards[sel].config.irq = hw_config->irq; - snd_installed_cards[sel].config.dma = hw_config->dma; - snd_installed_cards[sel].config.dma2 = hw_config->dma2; - snd_installed_cards[sel].config.name = hw_config->name; - snd_installed_cards[sel].config.always_detect = hw_config->always_detect; - snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; - snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; - snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; - - if ((drv = snd_find_driver(snd_installed_cards[sel].card_type)) == -1) - { - snd_installed_cards[sel].enabled = 0; - DEB(printk("Failed to find driver\n")); - return 0; - } - DEB(printk("Driver name '%s'\n", sound_drivers[drv].name)); - - hw_config->card_subtype = - snd_installed_cards[sel].config.card_subtype = - sound_drivers[drv].card_subtype; - - if (sound_drivers[drv].probe(hw_config)) - { - DEB(printk("Hardware probed OK\n")); - return 1; - } - DEB(printk("Failed to find hardware\n")); - snd_installed_cards[sel].enabled = 0; /* + snd_installed_cards[sel].for_driver_use = NULL; + snd_installed_cards[sel].config.io_base = hw_config->io_base; + snd_installed_cards[sel].config.irq = hw_config->irq; + snd_installed_cards[sel].config.dma = hw_config->dma; + snd_installed_cards[sel].config.dma2 = hw_config->dma2; + snd_installed_cards[sel].config.name = hw_config->name; + snd_installed_cards[sel].config.always_detect = hw_config->always_detect; + snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; + snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; + snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; + + if ((drv = snd_find_driver(snd_installed_cards[sel].card_type)) == -1) + { + snd_installed_cards[sel].enabled = 0; + DEB(printk(KERN_DEBUG "Failed to find driver\n")); + return 0; + } + DEB(printk(KERN_DEBUG "Driver name '%s'\n", sound_drivers[drv].name)); + + hw_config->card_subtype = snd_installed_cards[sel].config.card_subtype = sound_drivers[drv].card_subtype; + + if (sound_drivers[drv].probe(hw_config)) + { + DEB(printk(KERN_DEBUG "Hardware probed OK\n")); + return 1; + } + DEB(printk("Failed to find hardware\n")); + snd_installed_cards[sel].enabled = 0; /* * Mark as not detected */ - return 0; - } + return 0; + } return 0; } -int -sndtable_init_card(int unit, struct address_info *hw_config) +int sndtable_init_card(int unit, struct address_info *hw_config) { - int i, n = num_sound_cards; + int i, n = num_sound_cards; DEB(printk("sndtable_init_card(%d) entered\n", unit)); if (!unit) - { - sndtable_init(); - return 1; - } + { + sndtable_init(); + return 1; + } for (i = 0; i < n && snd_installed_cards[i].card_type; i++) + { if (snd_installed_cards[i].card_type == unit) - { - int drv; + { + int drv; - snd_installed_cards[i].config.io_base = hw_config->io_base; - snd_installed_cards[i].config.irq = hw_config->irq; - snd_installed_cards[i].config.dma = hw_config->dma; - snd_installed_cards[i].config.dma2 = hw_config->dma2; - snd_installed_cards[i].config.name = hw_config->name; - snd_installed_cards[i].config.always_detect = hw_config->always_detect; - snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1; - snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2; - snd_installed_cards[i].config.card_subtype = hw_config->card_subtype; + snd_installed_cards[i].config.io_base = hw_config->io_base; + snd_installed_cards[i].config.irq = hw_config->irq; + snd_installed_cards[i].config.dma = hw_config->dma; + snd_installed_cards[i].config.dma2 = hw_config->dma2; + snd_installed_cards[i].config.name = hw_config->name; + snd_installed_cards[i].config.always_detect = hw_config->always_detect; + snd_installed_cards[i].config.driver_use_1 = hw_config->driver_use_1; + snd_installed_cards[i].config.driver_use_2 = hw_config->driver_use_2; + snd_installed_cards[i].config.card_subtype = hw_config->card_subtype; - if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) - snd_installed_cards[i].enabled = 0; /* + if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) == -1) + snd_installed_cards[i].enabled = 0; /* * Mark as not detected */ - else - { - - DEB(printk("Located card - calling attach routine\n")); - sound_drivers[drv].attach(hw_config); - - DEB(printk("attach routine finished\n")); - } - start_services(); - return 1; - } + else + { + DEB(printk(KERN_DEBUG "Located card - calling attach routine\n")); + sound_drivers[drv].attach(hw_config); + + DEB(printk("attach routine finished\n")); + } + start_services(); + return 1; + } + } DEB(printk("sndtable_init_card: No card defined with type=%d, num cards: %d\n", unit, num_sound_cards)); return 0; } -int -sndtable_get_cardcount(void) +int sndtable_get_cardcount(void) { return num_audiodevs + num_mixers + num_synths + num_midis; } -int -sndtable_identify_card(char *name) +int sndtable_identify_card(char *name) { - int i, n = num_sound_drivers; + int i, n = num_sound_drivers; if (name == NULL) return 0; for (i = 0; i < n; i++) + { if (sound_drivers[i].driver_id != NULL) - { - char *id = sound_drivers[i].driver_id; - int j; - - for (j = 0; j < 80 && name[j] == id[j]; j++) - if (id[j] == 0 && name[j] == 0) /* Match */ - return sound_drivers[i].card_type; - } + { + char *id = sound_drivers[i].driver_id; + int j; + + for (j = 0; j < 80 && name[j] == id[j]; j++) + if (id[j] == 0 && name[j] == 0) /* Match */ + return sound_drivers[i].card_type; + } + } return 0; } -void -sound_setup(char *str, int *ints) +void sound_setup(char *str, int *ints) { - int i, n = num_sound_cards; + int i, n = num_sound_cards; /* - * First disable all drivers + * First disable all drivers */ for (i = 0; i < n && snd_installed_cards[i].card_type; i++) @@ -338,70 +325,69 @@ if (ints[0] == 0 || ints[1] == 0) return; /* - * Then enable them one by time + * Then enable them one by time */ for (i = 1; i <= ints[0]; i++) - { - int card_type, ioaddr, irq, dma, dma2, - ptr, j; - unsigned int val; - - val = (unsigned int) ints[i]; - - card_type = (val & 0x0ff00000) >> 20; - - if (card_type > 127) - { - /* - * Add any future extensions here - */ - return; - } - ioaddr = (val & 0x000fff00) >> 8; - irq = (val & 0x000000f0) >> 4; - dma = (val & 0x0000000f); - dma2 = (val & 0xf0000000) >> 28; - - ptr = -1; - for (j = 0; j < n && ptr == -1; j++) - if (snd_installed_cards[j].card_type == card_type && - !snd_installed_cards[j].enabled) /* + { + int card_type, ioaddr, irq, dma, dma2, ptr, j; + unsigned int val; + + val = (unsigned int) ints[i]; + card_type = (val & 0x0ff00000) >> 20; + + if (card_type > 127) + { + /* + * Add any future extensions here + */ + return; + } + ioaddr = (val & 0x000fff00) >> 8; + irq = (val & 0x000000f0) >> 4; + dma = (val & 0x0000000f); + dma2 = (val & 0xf0000000) >> 28; + + ptr = -1; + for (j = 0; j < n && ptr == -1; j++) + { + if (snd_installed_cards[j].card_type == card_type && + !snd_installed_cards[j].enabled)/* * Not already found */ - ptr = j; + ptr = j; + } - if (ptr == -1) - printk("Sound: Invalid setup parameter 0x%08x\n", val); - else - { - snd_installed_cards[ptr].enabled = 1; - snd_installed_cards[ptr].config.io_base = ioaddr; - snd_installed_cards[ptr].config.irq = irq; - snd_installed_cards[ptr].config.dma = dma; - snd_installed_cards[ptr].config.dma2 = dma2; - snd_installed_cards[ptr].config.name = NULL; - snd_installed_cards[ptr].config.always_detect = 0; - snd_installed_cards[ptr].config.driver_use_1 = 0; - snd_installed_cards[ptr].config.driver_use_2 = 0; - snd_installed_cards[ptr].config.card_subtype = 0; - } - } + if (ptr == -1) + printk(KERN_ERR "Sound: Invalid setup parameter 0x%08x\n", val); + else + { + snd_installed_cards[ptr].enabled = 1; + snd_installed_cards[ptr].config.io_base = ioaddr; + snd_installed_cards[ptr].config.irq = irq; + snd_installed_cards[ptr].config.dma = dma; + snd_installed_cards[ptr].config.dma2 = dma2; + snd_installed_cards[ptr].config.name = NULL; + snd_installed_cards[ptr].config.always_detect = 0; + snd_installed_cards[ptr].config.driver_use_1 = 0; + snd_installed_cards[ptr].config.driver_use_2 = 0; + snd_installed_cards[ptr].config.card_subtype = 0; + } + } } -struct address_info - * -sound_getconf(int card_type) +struct address_info * sound_getconf(int card_type) { - int j, ptr; - int n = num_sound_cards; + int j, ptr; + int n = num_sound_cards; ptr = -1; for (j = 0; j < n && ptr == -1 && snd_installed_cards[j].card_type; j++) + { if (snd_installed_cards[j].card_type == card_type) ptr = j; - + } if (ptr == -1) return (struct address_info *) NULL; @@ -410,60 +396,53 @@ -int -sound_install_audiodrv(int vers, - char *name, - struct audio_driver *driver, - int driver_size, - int flags, - unsigned int format_mask, - void *devc, - int dma1, - int dma2) +int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, + int driver_size, int flags, unsigned int format_mask, + void *devc, int dma1, int dma2) { #ifdef CONFIG_AUDIO struct audio_driver *d; struct audio_operations *op; - int l, num; + int l, num; - if (vers != AUDIO_DRIVER_VERSION || - driver_size > sizeof(struct audio_driver)) - { - printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name); - return -(EINVAL); - } + if (vers != AUDIO_DRIVER_VERSION || driver_size > sizeof(struct audio_driver)) + { + printk(KERN_ERR "Sound: Incompatible audio driver for %s\n", name); + return -(EINVAL); + } num = sound_alloc_audiodev(); if (num == -1) - { - printk(KERN_ERR "sound: Too many audio drivers\n"); - return -(EBUSY); - } + { + printk(KERN_ERR "sound: Too many audio drivers\n"); + return -(EBUSY); + } d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_driver))); sound_mem_sizes[sound_nblocks] = sizeof(struct audio_driver); if (sound_nblocks < 1024) - sound_nblocks++;; + sound_nblocks++; op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct audio_operations))); sound_mem_sizes[sound_nblocks] = sizeof(struct audio_operations); if (sound_nblocks < 1024) - sound_nblocks++;; + sound_nblocks++; if (d == NULL || op == NULL) - { - printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name); - sound_unload_audiodev(num); - return -(ENOMEM); - } + { + printk(KERN_ERR "Sound: Can't allocate driver for (%s)\n", name); + sound_unload_audiodev(num); + return -(ENOMEM); + } memset((char *) op, 0, sizeof(struct audio_operations)); + init_waitqueue(&op->in_sleeper); + init_waitqueue(&op->out_sleeper); if (driver_size < sizeof(struct audio_driver)) - memset((char *) d, 0, sizeof(struct audio_driver)); + memset((char *) d, 0, sizeof(struct audio_driver)); memcpy((char *) d, (char *) driver, driver_size); op->d = d; - l = strlen(name) + 1; if (l > sizeof(op->name)) l = sizeof(op->name); @@ -473,9 +452,9 @@ op->format_mask = format_mask; op->devc = devc; -/* - * Hardcoded defaults - */ + /* + * Hardcoded defaults + */ audio_devs[num] = op; DMAbuf_init(num, dma1, dma2); @@ -487,41 +466,40 @@ #endif } -int -sound_install_mixer(int vers, - char *name, - struct mixer_operations *driver, - int driver_size, - void *devc) +int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, + int driver_size, void *devc) { struct mixer_operations *op; - int l; + int l; - int n = sound_alloc_mixerdev(); + int n = sound_alloc_mixerdev(); if (n == -1) - { - printk(KERN_ERR "Sound: Too many mixer drivers\n"); - return -(EBUSY); - } + { + printk(KERN_ERR "Sound: Too many mixer drivers\n"); + return -EBUSY; + } if (vers != MIXER_DRIVER_VERSION || - driver_size > sizeof(struct mixer_operations)) - { - printk(KERN_ERR "Sound: Incompatible mixer driver for %s\n", name); - return -(EINVAL); - } + driver_size > sizeof(struct mixer_operations)) + { + printk(KERN_ERR "Sound: Incompatible mixer driver for %s\n", name); + return -EINVAL; + } + + /* FIXME: This leaks a mixer_operations struct every time its called + until you unload sound! */ + op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(struct mixer_operations))); sound_mem_sizes[sound_nblocks] = sizeof(struct mixer_operations); if (sound_nblocks < 1024) - sound_nblocks++;; + sound_nblocks++; if (op == NULL) - { - printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name); - return -(ENOMEM); - } + { + printk(KERN_ERR "Sound: Can't allocate mixer driver for (%s)\n", name); + return -ENOMEM; + } memset((char *) op, 0, sizeof(struct mixer_operations)); - memcpy((char *) op, (char *) driver, driver_size); l = strlen(name) + 1; @@ -535,108 +513,99 @@ return n; } -void -sound_unload_audiodev(int dev) +void sound_unload_audiodev(int dev) { if (dev != -1) audio_devs[dev] = NULL; } -int -sound_alloc_audiodev(void) +int sound_alloc_audiodev(void) { - int i; + int i; for (i = 0; i < MAX_AUDIO_DEV; i++) - { - if (audio_devs[i] == NULL) - { - if (i >= num_audiodevs) - num_audiodevs = i + 1; - return i; - } - } + { + if (audio_devs[i] == NULL) + { + if (i >= num_audiodevs) + num_audiodevs = i + 1; + return i; + } + } return -1; } -int -sound_alloc_mididev(void) +int sound_alloc_mididev(void) { - int i; + int i; for (i = 0; i < MAX_MIDI_DEV; i++) - { - if (midi_devs[i] == NULL) - { - if (i >= num_midis) - num_midis++; - return i; - } - } - + { + if (midi_devs[i] == NULL) + { + if (i >= num_midis) + num_midis++; + return i; + } + } return -1; } -int -sound_alloc_synthdev(void) +int sound_alloc_synthdev(void) { - int i; + int i; for (i = 0; i < MAX_SYNTH_DEV; i++) - { - if (synth_devs[i] == NULL) - { - if (i >= num_synths) - num_synths++; - return i; - } - } + { + if (synth_devs[i] == NULL) + { + if (i >= num_synths) + num_synths++; + return i; + } + } return -1; } -int -sound_alloc_mixerdev(void) +int sound_alloc_mixerdev(void) { - int i; + int i; for (i = 0; i < MAX_MIXER_DEV; i++) - { - if (mixer_devs[i] == NULL) - { - if (i >= num_mixers) - num_mixers++; - return i; - } - } + { + if (mixer_devs[i] == NULL) + { + if (i >= num_mixers) + num_mixers++; + return i; + } + } return -1; } -int -sound_alloc_timerdev(void) +int sound_alloc_timerdev(void) { - int i; + int i; for (i = 0; i < MAX_TIMER_DEV; i++) - { - if (sound_timer_devs[i] == NULL) - { - if (i >= num_sound_timers) - num_sound_timers++; - return i; - } - } + { + if (sound_timer_devs[i] == NULL) + { + if (i >= num_sound_timers) + num_sound_timers++; + return i; + } + } return -1; } -void -sound_unload_mixerdev(int dev) +void sound_unload_mixerdev(int dev) { if (dev != -1) mixer_devs[dev] = NULL; } -void -sound_unload_mididev(int dev) +void sound_unload_mididev(int dev) { #ifdef CONFIG_MIDI if (dev != -1) @@ -644,16 +613,15 @@ #endif } -void -sound_unload_synthdev(int dev) +void sound_unload_synthdev(int dev) { if (dev != -1) synth_devs[dev] = NULL; } -void -sound_unload_timerdev(int dev) +void sound_unload_timerdev(int dev) { if (dev != -1) sound_timer_devs[dev] = NULL; } + 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 Tue Dec 23 22:52:02 1997 +++ new/linux/drivers/sound/dev_table.h Thu Feb 19 23:46:14 1998 @@ -2,8 +2,8 @@ * dev_table.h * * Global definitions for device call tables - */ -/* + * + * * Copyright (C) by Hannu Savolainen 1993-1997 * * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) @@ -21,6 +21,7 @@ * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h) * Numbers 1000 to N are reserved for driver's internal use. */ + #define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */ #define SNDCARD_SBPNP 29 #define SNDCARD_OPL3SA1 38 @@ -52,7 +53,8 @@ extern int sound_started; -struct driver_info { +struct driver_info +{ char *driver_id; int card_subtype; /* Driver specific. Usually 0 */ int card_type; /* From soundcard.h */ @@ -62,7 +64,8 @@ void (*unload) (struct address_info *hw_config); }; -struct card_info { +struct card_info +{ int card_type; /* Link (search key) to the driver list */ struct address_info config; int enabled; @@ -79,7 +82,8 @@ #define DMODE_OUTPUT PCM_ENABLE_OUTPUT #define DMODE_INPUT PCM_ENABLE_INPUT -struct dma_buffparms { +struct dma_buffparms +{ int dma_mode; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */ int closing; @@ -156,17 +160,19 @@ * Structure for use with various microcontrollers and DSP processors * in the recent soundcards. */ -typedef struct coproc_operations { - char name[64]; - int (*open) (void *devc, int sub_device); - void (*close) (void *devc, int sub_device); - int (*ioctl) (void *devc, unsigned int cmd, caddr_t arg, int local); - void (*reset) (void *devc); +typedef struct coproc_operations +{ + char name[64]; + int (*open) (void *devc, int sub_device); + void (*close) (void *devc, int sub_device); + int (*ioctl) (void *devc, unsigned int cmd, caddr_t arg, int local); + void (*reset) (void *devc); - void *devc; /* Driver specific info */ - } coproc_operations; + void *devc; /* Driver specific info */ +} coproc_operations; -struct audio_driver { +struct audio_driver +{ int (*open) (int dev, int mode); void (*close) (int dev); void (*output_block) (int dev, unsigned long buf, @@ -190,7 +196,8 @@ void (*preprocess_read)(int dev); /* Device spesific preprocessing for read data */ }; -struct audio_operations { +struct audio_operations +{ char name[128]; int flags; #define NOTHING_SPECIAL 0x00 @@ -214,11 +221,33 @@ int min_fragment; /* 0 == unlimited */ int max_fragment; /* 0 == unlimited */ int parent_dev; /* 0 -> no parent, 1 to n -> parent=parent_dev+1 */ + + /* fields formerly in dmabuf.c */ + struct wait_queue *in_sleeper; + struct wait_queue *out_sleeper; + + /* fields formerly in audio.c */ + int audio_mode; + /* why dont we use file->f_flags & O_NONBLOCK for the following? - ts */ + int dev_nblock; /* 1 if in nonblocking mode */ + +#define AM_NONE 0 +#define AM_WRITE OPEN_WRITE +#define AM_READ OPEN_READ + + int local_format; + int audio_format; + int local_conversion; +#define CNV_MU_LAW 0x00000001 + + /* large structures at the end to keep offsets small */ + struct dma_buffparms dmaps[2]; }; int *load_mixer_volumes(char *name, int *levels, int present); -struct mixer_operations { +struct mixer_operations +{ char id[16]; char name[64]; int (*ioctl) (int dev, unsigned int cmd, caddr_t arg); @@ -227,7 +256,8 @@ int modify_counter; }; -struct synth_operations { +struct synth_operations +{ char *id; /* Unique identifier (ASCII) max 29 char */ struct synth_info *info; int midi_dev; @@ -263,20 +293,23 @@ int sysex_ptr; }; -struct midi_input_info { /* MIDI input scanner variables */ +struct midi_input_info +{ + /* MIDI input scanner variables */ #define MI_MAX 10 - int m_busy; - unsigned char m_buf[MI_MAX]; - unsigned char m_prev_status; /* For running status */ - int m_ptr; + int m_busy; + unsigned char m_buf[MI_MAX]; + unsigned char m_prev_status; /* For running status */ + int m_ptr; #define MST_INIT 0 #define MST_DATA 1 #define MST_SYSEX 2 - int m_state; - int m_left; - }; + int m_state; + int m_left; +}; -struct midi_operations { +struct midi_operations +{ struct midi_info info; struct synth_operations *converter; struct midi_input_info in_info; @@ -297,15 +330,17 @@ void *devc; }; -struct sound_lowlev_timer { - int dev; - int priority; - unsigned int (*tmr_start)(int dev, unsigned int usecs); - void (*tmr_disable)(int dev); - void (*tmr_restart)(int dev); - }; +struct sound_lowlev_timer +{ + int dev; + int priority; + unsigned int (*tmr_start)(int dev, unsigned int usecs); + void (*tmr_disable)(int dev); + void (*tmr_restart)(int dev); +}; -struct sound_timer_operations { +struct sound_timer_operations +{ struct sound_timer_info info; int priority; int devlink; @@ -319,91 +354,94 @@ #ifdef _DEV_TABLE_C_ - struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; int num_audiodevs = 0; - struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0; - struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0; - struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0; +struct audio_operations *audio_devs[MAX_AUDIO_DEV] = {NULL}; int num_audiodevs = 0; +struct mixer_operations *mixer_devs[MAX_MIXER_DEV] = {NULL}; int num_mixers = 0; +struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV] = {NULL}; int num_synths = 0; +struct midi_operations *midi_devs[MAX_MIDI_DEV] = {NULL}; int num_midis = 0; #if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) && !defined(VMIDI) - extern struct sound_timer_operations default_sound_timer; - struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = - {&default_sound_timer, NULL}; - int num_sound_timers = 1; +extern struct sound_timer_operations default_sound_timer; +struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = { + &default_sound_timer, NULL +}; +int num_sound_timers = 1; #else - struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = - {NULL}; - int num_sound_timers = 0; +struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = { + NULL +}; +int num_sound_timers = 0; #endif /* * List of low level drivers compiled into the kernel. */ - struct driver_info sound_drivers[] = { +struct driver_info sound_drivers[] = +{ #if defined(CONFIG_PSS) && !defined(CONFIG_PSS_MODULE) - {"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, - {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, - {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, + {"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, + {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, + {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, #endif #if defined(CONFIG_GUS) && !defined(CONFIG_GUS_MODULE) #ifdef CONFIG_GUS16 - {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, + {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, #endif -#ifdef CONFIG_GUSHW - {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, - {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, +#ifdef CONFIG_GUS + {"GUS", 0, SNDCARD_GUS, "Gravis Ultrasound", attach_gus_card, probe_gus, unload_gus}, + {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, #endif #endif #if defined(CONFIG_MSS) && !defined(CONFIG_MSS_MODULE) - {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, + {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, /* Compaq Deskpro XL */ - {"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound}, + {"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound}, #endif #ifdef CONFIG_MAD16 - {"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)", attach_mad16, probe_mad16, unload_mad16}, - {"MAD16MPU", 0, SNDCARD_MAD16_MPU, "MAD16/Mozart (MPU)", attach_mad16_mpu, probe_mad16_mpu, unload_mad16_mpu}, + {"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)", attach_mad16, probe_mad16, unload_mad16}, + {"MAD16MPU", 0, SNDCARD_MAD16_MPU, "MAD16/Mozart (MPU)", attach_mad16_mpu, probe_mad16_mpu, unload_mad16_mpu}, #endif #ifdef CONFIG_CS4232 - {"CS4232", 0, SNDCARD_CS4232, "CS4232", attach_cs4232, probe_cs4232, unload_cs4232}, - {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu}, + {"CS4232", 0, SNDCARD_CS4232, "CS4232", attach_cs4232, probe_cs4232, unload_cs4232}, + {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu}, #endif #if defined(CONFIG_YM3812) && !defined(CONFIG_YM3812_MODULE) - {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib}, + {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib}, #endif #if defined(CONFIG_PAS) && !defined(CONFIG_PAS_MODULE) - {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas}, + {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas}, #endif #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) && !defined(CONFIG_MPU401_MODULE) - {"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401}, + {"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401}, #endif #if defined(CONFIG_UART401) && defined(CONFIG_MIDI) && !defined(CONFIG_UART401_MODULE) {"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)", attach_uart401, probe_uart401, unload_uart401}, #endif #if defined(CONFIG_MAUI) && !defined(CONFIG_MAUI_MODULE) - {"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui}, + {"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui}, #endif #if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) && !defined(CONFIG_UART6850_MODULE) - {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, + {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, #endif #if defined(CONFIG_SBDSP) && !defined(CONFIG_SBDSP_MODULE) - {"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb}, - {"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb}, + {"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb}, + {"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb}, -# ifdef CONFIG_MIDI - {"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU-401", attach_sbmpu, probe_sbmpu, unload_sbmpu}, -# endif +#ifdef CONFIG_MIDI + {"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU-401", attach_sbmpu, probe_sbmpu, unload_sbmpu}, +#endif #endif -#ifdef CONFIG_SSCAPEHW - {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, - {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound}, +#ifdef CONFIG_SSCAPE + {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, + {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound}, #endif #ifdef CONFIG_OPL3SA1 @@ -413,205 +451,199 @@ #endif #if defined (CONFIG_TRIX) && !defined(CONFIG_TRIX_MODULE) - {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss}, - {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, - {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, + {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss}, + {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, + {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, #endif #if defined(CONFIG_SOFTOSS) && !defined(CONFIG_SOFTOSS_MODULE) - {"SOFTSYN", 0, SNDCARD_SOFTOSS, "SoftOSS Virtual Wave Table", + {"SOFTSYN", 0, SNDCARD_SOFTOSS, "SoftOSS Virtual Wave Table", attach_softsyn_card, probe_softsyn, unload_softsyn}, #endif #if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI) && !defined(CONFIG_VMIDI_MODULE) - {"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi}, + {"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi}, #endif + {NULL, 0, 0, "*?*", NULL, NULL, NULL} +}; - - - - {NULL, 0, 0, "*?*", NULL, NULL, NULL} - }; - - int num_sound_drivers = - sizeof(sound_drivers) / sizeof (struct driver_info); +int num_sound_drivers = sizeof(sound_drivers) / sizeof (struct driver_info); #ifndef FULL_SOUND + /* * List of devices actually configured in the system. * * Note! The detection order is significant. Don't change it. */ - struct card_info snd_installed_cards[] = { +struct card_info snd_installed_cards[] = +{ #ifdef CONFIG_PSS - {SNDCARD_PSS, {PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE}, -# ifdef PSS_MPU_BASE - {SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -# endif -# ifdef PSS_MSS_BASE - {SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE}, -# endif + {SNDCARD_PSS, {CONFIG_PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE}, +#ifdef CONFIG_PSS_MPU_BASE + {SNDCARD_PSS_MPU, {CONFIG_PSS_MPU_BASE, CONFIG_PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, +#endif +#ifdef CONFIG_PSS_MSS_BASE + {SNDCARD_PSS_MSS, {CONFIG_PSS_MSS_BASE, CONFIG_PSS_MSS_IRQ, CONFIG_PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE}, +#endif #endif #ifdef CONFIG_TRIX -#ifndef TRIX_DMA2 -#define TRIX_DMA2 TRIX_DMA +#ifndef CONFIG_TRIX_DMA2 +#define CONFIG_TRIX_DMA2 CONFIG_TRIX_DMA +#endif + {SNDCARD_TRXPRO, {CONFIG_TRIX_BASE, CONFIG_TRIX_IRQ, CONFIG_TRIX_DMA, CONFIG_TRIX_DMA2}, SND_DEFAULT_ENABLE}, +#ifdef CONFIG_TRIX_SB_BASE + {SNDCARD_TRXPRO_SB, {CONFIG_TRIX_SB_BASE, CONFIG_TRIX_SB_IRQ, CONFIG_TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE}, +#endif +#ifdef CONFIG_TRIX_MPU_BASE + {SNDCARD_TRXPRO_MPU, {CONFIG_TRIX_MPU_BASE, CONFIG_TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif - {SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA, TRIX_DMA2}, SND_DEFAULT_ENABLE}, -# ifdef TRIX_SB_BASE - {SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA, -1}, SND_DEFAULT_ENABLE}, -# endif -# ifdef TRIX_MPU_BASE - {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -# endif #endif #ifdef CONFIG_OPL3SA1 - {SNDCARD_OPL3SA1, {OPL3SA1_BASE, OPL3SA1_IRQ, OPL3SA1_DMA, OPL3SA1_DMA2}, SND_DEFAULT_ENABLE}, -# ifdef OPL3SA1_MPU_BASE - {SNDCARD_OPL3SA1_MPU, {OPL3SA1_MPU_BASE, OPL3SA1_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -# endif + {SNDCARD_OPL3SA1, {CONFIG_OPL3SA1_BASE, CONFIG_OPL3SA1_IRQ, CONFIG_OPL3SA1_DMA, CONFIG_OPL3SA1_DMA2}, SND_DEFAULT_ENABLE}, +#ifdef CONFIG_OPL3SA1_MPU_BASE + {SNDCARD_OPL3SA1_MPU, {CONFIG_OPL3SA1_MPU_BASE, CONFIG_OPL3SA1_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, +#endif #endif #ifdef CONFIG_SOFTOSS - {SNDCARD_SOFTOSS, {0, 0, -1, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_SOFTOSS, {0, 0, -1, -1}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_SSCAPE - {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, - {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_SSCAPE, {CONFIG_SSCAPE_BASE, CONFIG_SSCAPE_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_SSCAPE_MSS, {CONFIG_SSCAPE_MSS_BASE, CONFIG_SSCAPE_MSS_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_MAD16 -#ifndef MAD16_DMA2 -#define MAD16_DMA2 MAD16_DMA +#ifndef CONFIG_MAD16_DMA2 +#define CONFIG_MAD16_DMA2 CONFIG_MAD16_DMA +#endif + {SNDCARD_MAD16, {CONFIG_MAD16_BASE, CONFIG_MAD16_IRQ, CONFIG_MAD16_DMA, CONFIG_MAD16_DMA2}, SND_DEFAULT_ENABLE}, +#ifdef CONFIG_MAD16_MPU_BASE + {SNDCARD_MAD16_MPU, {CONFIG_MAD16_MPU_BASE, CONFIG_MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif - {SNDCARD_MAD16, {MAD16_BASE, MAD16_IRQ, MAD16_DMA, MAD16_DMA2}, SND_DEFAULT_ENABLE}, -# ifdef MAD16_MPU_BASE - {SNDCARD_MAD16_MPU, {MAD16_MPU_BASE, MAD16_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -# endif #endif #ifdef CONFIG_CS4232 -#ifndef CS4232_DMA2 -#define CS4232_DMA2 CS4232_DMA +#ifndef CONFIG_CS4232_DMA2 +#define CONFIG_CS4232_DMA2 CONFIG_CS4232_DMA +#endif +#ifdef CONFIG_CS4232_MPU_BASE + {SNDCARD_CS4232_MPU, {CONFIG_CS4232_MPU_BASE, CONFIG_CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif -# ifdef CS4232_MPU_BASE - {SNDCARD_CS4232_MPU, {CS4232_MPU_BASE, CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, -# endif - {SNDCARD_CS4232, {CS4232_BASE, CS4232_IRQ, CS4232_DMA, CS4232_DMA2}, SND_DEFAULT_ENABLE}, + {SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_MSS -# ifndef MSS_DMA2 -# define MSS_DMA2 -1 -# endif - -# ifdef DESKPROXL - {SNDCARD_DESKPROXL, {MSS_BASE, MSS_IRQ, MSS_DMA, MSS_DMA2}, SND_DEFAULT_ENABLE}, -# else - {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, MSS_DMA2}, SND_DEFAULT_ENABLE}, -# endif -# ifdef MSS2_BASE - {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, MSS2_DMA2}, SND_DEFAULT_ENABLE}, -# endif +#ifndef CONFIG_MSS_DMA2 +#define CONFIG_MSS_DMA2 -1 +#endif + +#ifdef DESKPROXL + {SNDCARD_DESKPROXL, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE}, +#else + {SNDCARD_MSS, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE}, +#endif +#ifdef MSS2_BASE + {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, MSS2_DMA2}, SND_DEFAULT_ENABLE}, +#endif #endif #ifdef CONFIG_PAS - {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_PAS, {CONFIG_PAS_BASE, CONFIG_PAS_IRQ, CONFIG_PAS_DMA, -1}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_SB -# ifndef SBC_DMA -# define SBC_DMA 1 -# endif -# ifndef SB_DMA2 -# define SB_DMA2 -1 -# endif - {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, SB_DMA2}, SND_DEFAULT_ENABLE}, -# ifdef SB2_BASE - {SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE}, -# endif +#ifndef CONFIG_SB_DMA +#define CONFIG_SB_DMA 1 +#endif +#ifndef CONFIG_SB_DMA2 +#define CONFIG_SB_DMA2 -1 +#endif + {SNDCARD_SB, {CONFIG_SB_BASE, CONFIG_SB_IRQ, CONFIG_SB_DMA, CONFIG_SB_DMA2}, SND_DEFAULT_ENABLE}, +#ifdef SB2_BASE + {SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE}, +#endif #endif #if defined(CONFIG_MAUI) - {SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_MAUI, {CONFIG_MAUI_BASE, CONFIG_MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #if defined(CONFIG_MPU401) && defined(CONFIG_MIDI) - {SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_MPU401, {CONFIG_MPU_BASE, CONFIG_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #ifdef MPU2_BASE - {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #ifdef MPU3_BASE - {SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_MPU401, {MPU3_BASE, MPU3_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #endif #if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) - {SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_UART6850, {CONFIG_U6850_BASE, CONFIG_U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #if defined(CONFIG_SB) -#if defined(CONFIG_MIDI) && defined(SB_MPU_BASE) - {SNDCARD_SB16MIDI,{SB_MPU_BASE, SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, +#if defined(CONFIG_MIDI) && defined(CONFIG_SB_MPU_BASE) + {SNDCARD_SB16MIDI,{CONFIG_SB_MPU_BASE, CONFIG_SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #endif #ifdef CONFIG_GUS -#ifndef GUS_DMA2 -#define GUS_DMA2 GUS_DMA +#ifndef CONFIG_GUS_DMA2 +#define CONFIG_GUS_DMA2 CONFIG_GUS_DMA #endif #ifdef CONFIG_GUS16 - {SNDCARD_GUS16, {GUS16_BASE, GUS16_IRQ, GUS16_DMA, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_GUS16, {CONFIG_GUS16_BASE, CONFIG_GUS16_IRQ, CONFIG_GUS16_DMA, -1}, SND_DEFAULT_ENABLE}, #endif - {SNDCARD_GUS, {GUS_BASE, GUS_IRQ, GUS_DMA, GUS_DMA2}, SND_DEFAULT_ENABLE}, + {SNDCARD_GUS, {CONFIG_GUS_BASE, CONFIG_GUS_IRQ, CONFIG_GUS_DMA, CONFIG_GUS_DMA2}, SND_DEFAULT_ENABLE}, #endif #if defined(CONFIG_YM3812) - {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif #if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI) - {SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif - {0, {0}, 0} - }; + {0, {0}, 0} +}; - int num_sound_cards = - sizeof(snd_installed_cards) / sizeof (struct card_info); - static int max_sound_cards = - sizeof(snd_installed_cards) / sizeof (struct card_info); +int num_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); +static int max_sound_cards = sizeof(snd_installed_cards) / sizeof (struct card_info); #else - int num_sound_cards = 0; - struct card_info snd_installed_cards[20] = {{0}}; - static int max_sound_cards = 20; +int num_sound_cards = 0; +struct card_info snd_installed_cards[20] = {{0}}; +static int max_sound_cards = 20; #endif #if defined(MODULE) || (!defined(linux) && !defined(_AIX)) - int trace_init = 0; -# else - int trace_init = 1; -# endif +int trace_init = 0; +#else +int trace_init = 1; +#endif #else - extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs; - extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers; - extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths; - extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis; - extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV]; extern int num_sound_timers; - - extern struct driver_info sound_drivers[]; - extern int num_sound_drivers; - extern struct card_info snd_installed_cards[]; - extern int num_sound_cards; +extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; extern int num_audiodevs; +extern struct mixer_operations * mixer_devs[MAX_MIXER_DEV]; extern int num_mixers; +extern struct synth_operations * synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV]; extern int num_synths; +extern struct midi_operations * midi_devs[MAX_MIDI_DEV]; extern int num_midis; +extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV]; extern int num_sound_timers; + +extern struct driver_info sound_drivers[]; +extern int num_sound_drivers; +extern struct card_info snd_installed_cards[]; +extern int num_sound_cards; - extern int trace_init; +extern int trace_init; #endif /* _DEV_TABLE_C_ */ - void sndtable_init(void); int sndtable_get_cardcount (void); struct address_info *sound_getconf(int card_type); @@ -622,34 +654,20 @@ int sndtable_identify_card(char *name); void sound_setup (char *str, int *ints); -int sound_alloc_dmap (int dev, struct dma_buffparms *dmap, int chan); -void sound_free_dmap (int dev, struct dma_buffparms *dmap, int chn); extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info); int sndtable_probe (int unit, struct address_info *hw_config); int sndtable_init_card (int unit, struct address_info *hw_config); int sndtable_start_card (int unit, struct address_info *hw_config); void sound_timer_init (struct sound_lowlev_timer *t, char *name); -int sound_start_dma ( int dev, struct dma_buffparms *dmap, int chan, - unsigned long physaddr, - int count, int dma_mode, int autoinit); void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan); #define AUDIO_DRIVER_VERSION 2 #define MIXER_DRIVER_VERSION 2 -int sound_install_audiodrv(int vers, - char *name, - struct audio_driver *driver, - int driver_size, - int flags, - unsigned int format_mask, - void *devc, - int dma1, - int dma2); -int sound_install_mixer(int vers, - char *name, - struct mixer_operations *driver, - int driver_size, - void *devc); +int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, + int driver_size, int flags, unsigned int format_mask, + void *devc, int dma1, int dma2); +int sound_install_mixer(int vers, char *name, struct mixer_operations *driver, + int driver_size, void *devc); void sound_unload_audiodev(int dev); void sound_unload_mixerdev(int dev); diff -ur --new-file old/linux/drivers/sound/dmabuf.c new/linux/drivers/sound/dmabuf.c --- old/linux/drivers/sound/dmabuf.c Tue Dec 30 19:59:17 1997 +++ new/linux/drivers/sound/dmabuf.c Thu Mar 12 19:53:23 1998 @@ -9,6 +9,15 @@ * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. + * + * Thomas Sailer : moved several static variables into struct audio_operations + * (which is grossly misnamed btw.) because they have the same + * lifetime as the rest in there and dynamic allocation saves + * 12k or so + * Thomas Sailer : remove {in,out}_sleep_flag. It was used for the sleeper to + * determine if it was woken up by the expiring timeout or by + * an explicit wake_up. current->timeout can be used instead; + * if 0, the wakeup was due to the timeout. */ #include @@ -17,35 +26,133 @@ #include "sound_config.h" -#if defined(CONFIG_AUDIO) || defined(CONFIG_GUSHW) +#if defined(CONFIG_AUDIO) || defined(CONFIG_GUS) -static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] = -{NULL}; -static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = + +static void dma_reset_output(int dev); +static void dma_reset_input(int dev); +static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode); + + + +static int debugmem = 0; /* switched off by default */ +static int dma_buffsize = DSP_BUFFSIZE; + +static void dmabuf_set_timeout(struct dma_buffparms *dmap) { - {0}}; -static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] = -{NULL}; -static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = + unsigned long tmout; + + tmout = (dmap->fragment_size * HZ) / dmap->data_rate; + tmout += HZ / 5; /* Some safety distance */ + if (tmout < (HZ / 2)) + tmout = HZ / 2; + if (tmout > 20 * HZ) + tmout = 20 * HZ; + current->timeout = jiffies + tmout; +} + +static int sound_alloc_dmap(struct dma_buffparms *dmap) { - {0}}; + char *start_addr, *end_addr; + int i, dma_pagesize; + int sz, size; + + dmap->mapping_flags &= ~DMA_MAP_MAPPED; + + if (dmap->raw_buf != NULL) + return 0; /* Already done */ + if (dma_buffsize < 4096) + dma_buffsize = 4096; + dma_pagesize = (dmap->dma < 4) ? (64 * 1024) : (128 * 1024); + dmap->raw_buf = NULL; + dmap->buffsize = dma_buffsize; + if (dmap->buffsize > dma_pagesize) + dmap->buffsize = dma_pagesize; + start_addr = NULL; + /* + * Now loop until we get a free buffer. Try to get smaller buffer if + * it fails. Don't accept smaller than 8k buffer for performance + * reasons. + */ + while (start_addr == NULL && dmap->buffsize > PAGE_SIZE) { + for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1); + dmap->buffsize = PAGE_SIZE * (1 << sz); + start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz); + if (start_addr == NULL) + dmap->buffsize /= 2; + } -static int ndmaps = 0; + if (start_addr == NULL) { + printk(KERN_WARNING "Sound error: Couldn't allocate DMA buffer\n"); + return -ENOMEM; + } else { + /* make some checks */ + end_addr = start_addr + dmap->buffsize - 1; + + if (debugmem) + printk(KERN_DEBUG "sound: start 0x%lx, end 0x%lx\n", (long) start_addr, (long) end_addr); + + /* now check if it fits into the same dma-pagesize */ + + if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1)) + || end_addr >= (char *) (MAX_DMA_ADDRESS)) { + printk(KERN_ERR "sound: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, dmap->buffsize); + return -EFAULT; + } + } + dmap->raw_buf = start_addr; + dmap->raw_buf_phys = virt_to_bus(start_addr); -#define MAX_DMAP (MAX_AUDIO_DEV*2) + for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) + set_bit(PG_reserved, &mem_map[i].flags); + return 0; +} -static struct dma_buffparms dmaps[MAX_DMAP] = +static void sound_free_dmap(struct dma_buffparms *dmap) { - {0}}; + int sz, size, i; + unsigned long start_addr, end_addr; + + if (dmap->raw_buf == NULL) + return; + for (sz = 0, size = PAGE_SIZE; size < dmap->buffsize; sz++, size <<= 1); + + start_addr = (unsigned long) dmap->raw_buf; + end_addr = start_addr + dmap->buffsize; -static void dma_reset_output(int dev); -static void dma_reset_input(int dev); -static int local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode); + for (i = MAP_NR(start_addr); i <= MAP_NR(end_addr); i++) + clear_bit(PG_reserved, &mem_map[i].flags);; -static void -dma_init_buffers(int dev, struct dma_buffparms *dmap) + free_pages((unsigned long) dmap->raw_buf, sz); + dmap->raw_buf = NULL; + /* Remember the buffer is deleted so we dont Oops later */ + dmap->fragment_size = 0; +} + + +/* Intel version !!!!!!!!! */ + +static int sound_start_dma(struct dma_buffparms *dmap, unsigned long physaddr, int count, int dma_mode) { + unsigned long flags; + int chan = dmap->dma; + + /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ + save_flags(flags); + cli(); + disable_dma(chan); + clear_dma_ff(chan); + set_dma_mode(chan, dma_mode); + set_dma_addr(chan, physaddr); + set_dma_count(chan, count); + enable_dma(chan); + restore_flags(flags); + + return 0; +} +static void dma_init_buffers(struct dma_buffparms *dmap) +{ dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; dmap->byte_counter = 0; dmap->max_byte_counter = 8000 * 60 * 60; @@ -61,30 +168,24 @@ dmap->flags = DMA_BUSY; /* Other flags off */ } -static int -open_dmap(int dev, int mode, struct dma_buffparms *dmap, int chan) +static int open_dmap(struct audio_operations *adev, int mode, struct dma_buffparms *dmap) { + int err; + if (dmap->flags & DMA_BUSY) return -EBUSY; + if ((err = sound_alloc_dmap(dmap)) < 0) + return err; - { - int err; - - if ((err = sound_alloc_dmap(dev, dmap, chan)) < 0) - return err; + if (dmap->raw_buf == NULL) { + printk(KERN_WARNING "Sound: DMA buffers not available\n"); + return -ENOSPC; /* Memory allocation failed during boot */ } - - if (dmap->raw_buf == NULL) - { - printk("Sound: DMA buffers not available\n"); - return -ENOSPC; /* Memory allocation failed during boot */ - } - if (sound_open_dma(chan, audio_devs[dev]->name)) - { - printk("Unable to grab(2) DMA%d for the audio driver\n", chan); - return -EBUSY; - } - dma_init_buffers(dev, dmap); + if (sound_open_dma(dmap->dma, adev->name)) { + printk(KERN_WARNING "Unable to grab(2) DMA%d for the audio driver\n", dmap->dma); + return -EBUSY; + } + dma_init_buffers(dmap); dmap->open_mode = mode; dmap->subdivision = dmap->underrun_count = 0; dmap->fragment_size = 0; @@ -95,68 +196,52 @@ dmap->needs_reorg = 1; dmap->audio_callback = NULL; dmap->callback_parm = 0; - - - if (dmap->dma_mode & DMODE_OUTPUT) - { - out_sleep_flag[dev].opts = WK_NONE; - } else - { - in_sleep_flag[dev].opts = WK_NONE; - } - return 0; } -static void -close_dmap(int dev, struct dma_buffparms *dmap, int chan) +static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap) { - sound_close_dma(chan); - + sound_close_dma(dmap->dma); if (dmap->flags & DMA_BUSY) dmap->dma_mode = DMODE_NONE; dmap->flags &= ~DMA_BUSY; - disable_dma(dmap->dma); + sound_free_dmap(dmap); } static unsigned int default_set_bits(int dev, unsigned int bits) { mm_segment_t fs = get_fs(); - unsigned int r; set_fs(get_ds()); - r = audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SETFMT, (caddr_t)&bits); + audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SETFMT, (caddr_t)&bits); set_fs(fs); - return r; + return bits; } static int default_set_speed(int dev, int speed) { mm_segment_t fs = get_fs(); - int r; set_fs(get_ds()); - r = audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SPEED, (caddr_t)&speed); + audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SPEED, (caddr_t)&speed); set_fs(fs); - return r; + return speed; } static short default_set_channels(int dev, short channels) { int c = channels; mm_segment_t fs = get_fs(); - short r; set_fs(get_ds()); - r = audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_CHANNELS, (caddr_t)&c); + audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_CHANNELS, (caddr_t)&c); set_fs(fs); - return r; + return c; } -static void -check_driver(struct audio_driver *d) +static void check_driver(struct audio_driver *d) { if (d->set_speed == NULL) d->set_speed = default_set_speed; @@ -166,85 +251,55 @@ d->set_channels = default_set_channels; } -int -DMAbuf_open(int dev, int mode) +int DMAbuf_open(int dev, int mode) { - int retval; + struct audio_operations *adev = audio_devs[dev]; + int retval; struct dma_buffparms *dmap_in = NULL; struct dma_buffparms *dmap_out = NULL; - if (dev >= num_audiodevs || audio_devs[dev] == NULL) - { + if (!adev) return -ENXIO; - } - if (!audio_devs[dev]) - { - return -ENXIO; - } - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma; - } - check_driver(audio_devs[dev]->d); + if (!(adev->flags & DMA_DUPLEX)) + adev->dmap_in = adev->dmap_out; + check_driver(adev->d); - if ((retval = audio_devs[dev]->d->open(dev, mode)) < 0) + if ((retval = adev->d->open(dev, mode)) < 0) return retval; + dmap_out = adev->dmap_out; + dmap_in = adev->dmap_in; + if (dmap_in == dmap_out) + adev->flags &= ~DMA_DUPLEX; - dmap_out = audio_devs[dev]->dmap_out; - dmap_in = audio_devs[dev]->dmap_in; + if (mode & OPEN_WRITE) { + if ((retval = open_dmap(adev, mode, dmap_out)) < 0) { + adev->d->close(dev); + return retval; + } + } + adev->enable_bits = mode; - if (dmap_in == dmap_out) - audio_devs[dev]->flags &= ~DMA_DUPLEX; + if (mode == OPEN_READ || (mode != OPEN_WRITE && adev->flags & DMA_DUPLEX)) { + if ((retval = open_dmap(adev, mode, dmap_in)) < 0) { + adev->d->close(dev); + if (mode & OPEN_WRITE) + close_dmap(adev, dmap_out); + return retval; + } + } + adev->open_mode = mode; + adev->go = 1; - if (mode & OPEN_WRITE) - { - if ((retval = open_dmap(dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0) - { - audio_devs[dev]->d->close(dev); - return retval; - } - } - audio_devs[dev]->enable_bits = mode; - - if (mode == OPEN_READ || (mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - { - if ((retval = open_dmap(dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0) - { - audio_devs[dev]->d->close(dev); - - if (mode & OPEN_WRITE) - { - close_dmap(dev, dmap_out, audio_devs[dev]->dmap_out->dma); - } - return retval; - } - } - audio_devs[dev]->open_mode = mode; - audio_devs[dev]->go = 1; - - if (mode & OPEN_READ) - in_sleep_flag[dev].opts = WK_NONE; - - if (mode & OPEN_WRITE) - out_sleep_flag[dev].opts = WK_NONE; - - audio_devs[dev]->d->set_bits(dev, 8); - audio_devs[dev]->d->set_channels(dev, 1); - audio_devs[dev]->d->set_speed(dev, DSP_DEFAULT_SPEED); - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset(audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } + adev->d->set_bits(dev, 8); + adev->d->set_channels(dev, 1); + adev->d->set_speed(dev, DSP_DEFAULT_SPEED); + if (adev->dmap_out->dma_mode == DMODE_OUTPUT) + memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, + adev->dmap_out->bytes_in_use); return 0; } -void -DMAbuf_reset(int dev) +void DMAbuf_reset(int dev) { if (audio_devs[dev]->open_mode & OPEN_WRITE) dma_reset_output(dev); @@ -253,493 +308,333 @@ dma_reset_input(dev); } -static void -dma_reset_output(int dev) +static void dma_reset_output(int dev) { - unsigned long flags; - int tmout; - - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - + struct audio_operations *adev = audio_devs[dev]; + unsigned long flags; + struct dma_buffparms *dmap = adev->dmap_out; if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ return; -/* - * First wait until the current fragment has been played completely - */ + /* + * First wait until the current fragment has been played completely + */ save_flags(flags); cli(); + adev->dmap_out->flags |= DMA_SYNCING; - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - - audio_devs[dev]->dmap_out->underrun_count = 0; - if (!signal_pending(current) - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - -/* - * Finally shut the device off - */ + adev->dmap_out->underrun_count = 0; + if (!signal_pending(current) && adev->dmap_out->qlen && + adev->dmap_out->underrun_count == 0) { + dmabuf_set_timeout(dmap); + interruptible_sleep_on(&adev->out_sleeper); + current->timeout = 0; + } + adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_output) - audio_devs[dev]->d->halt_io(dev); + /* + * Finally shut the device off + */ + if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_output) + adev->d->halt_io(dev); else - audio_devs[dev]->d->halt_output(dev); - audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED; - restore_flags(flags); - + adev->d->halt_output(dev); + adev->dmap_out->flags &= ~DMA_STARTED; clear_dma_ff(dmap->dma); disable_dma(dmap->dma); + restore_flags(flags); dmap->byte_counter = 0; - reorganize_buffers(dev, audio_devs[dev]->dmap_out, 0); + reorganize_buffers(dev, adev->dmap_out, 0); dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; } -static void -dma_reset_input(int dev) +static void dma_reset_input(int dev) { - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + struct audio_operations *adev = audio_devs[dev]; + unsigned long flags; + struct dma_buffparms *dmap = adev->dmap_in; save_flags(flags); cli(); - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_input) - audio_devs[dev]->d->halt_io(dev); + if (!(adev->flags & DMA_DUPLEX) || !adev->d->halt_input) + adev->d->halt_io(dev); else - audio_devs[dev]->d->halt_input(dev); - audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED; + adev->d->halt_input(dev); + adev->dmap_in->flags &= ~DMA_STARTED; restore_flags(flags); dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; dmap->byte_counter = 0; - reorganize_buffers(dev, audio_devs[dev]->dmap_in, 1); + reorganize_buffers(dev, adev->dmap_in, 1); } -void -DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) +void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) { - if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT)) - return; /* Don't start DMA yet */ + struct audio_operations *adev = audio_devs[dev]; + if (!((adev->enable_bits * adev->go) & PCM_ENABLE_OUTPUT)) + return; /* Don't start DMA yet */ dmap->dma_mode = DMODE_OUTPUT; - if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - if (!(dmap->flags & DMA_STARTED)) - { - reorganize_buffers(dev, dmap, 0); - - if (audio_devs[dev]->d->prepare_for_output(dev, - dmap->fragment_size, dmap->nbufs)) - return; - - if (!(dmap->flags & DMA_NODMA)) - { - local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_WRITE); - } - dmap->flags |= DMA_STARTED; - } - if (dmap->counts[dmap->qhead] == 0) - dmap->counts[dmap->qhead] = dmap->fragment_size; - - dmap->dma_mode = DMODE_OUTPUT; - audio_devs[dev]->d->output_block(dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } + if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { + if (!(dmap->flags & DMA_STARTED)) { + reorganize_buffers(dev, dmap, 0); + if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs)) + return; + if (!(dmap->flags & DMA_NODMA)) + local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_WRITE); + dmap->flags |= DMA_STARTED; + } + if (dmap->counts[dmap->qhead] == 0) + dmap->counts[dmap->qhead] = dmap->fragment_size; + dmap->dma_mode = DMODE_OUTPUT; + adev->d->output_block(dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, + dmap->counts[dmap->qhead], 1); + if (adev->d->trigger) + adev->d->trigger(dev,adev->enable_bits * adev->go); + } dmap->flags |= DMA_ACTIVE; } -int -DMAbuf_sync(int dev) +int DMAbuf_sync(int dev) { - unsigned long flags; - int tmout, n = 0; + struct audio_operations *adev = audio_devs[dev]; + unsigned long flags; + int n = 0; + struct dma_buffparms *dmap; - if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) + if (!adev->go && (!adev->enable_bits & PCM_ENABLE_OUTPUT)) return 0; - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - save_flags(flags); - cli(); - - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - ; - if (dmap->qlen > 0) - if (!(dmap->flags & DMA_ACTIVE)) - DMAbuf_launch_output(dev, dmap); - ; - - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - - audio_devs[dev]->dmap_out->underrun_count = 0; - while (!signal_pending(current) - && n++ <= audio_devs[dev]->dmap_out->nbufs - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; - restore_flags(flags); - return audio_devs[dev]->dmap_out->qlen; - } - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - restore_flags(flags); - /* - * Some devices such as GUS have huge amount of on board RAM for the - * audio data. We have to wait until the device has finished playing. - */ - - save_flags(flags); - cli(); - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - { - while (!signal_pending(current) - && audio_devs[dev]->d->local_qlen(dev)) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - } - restore_flags(flags); - } - audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE; - return audio_devs[dev]->dmap_out->qlen; + if (adev->dmap_out->dma_mode == DMODE_OUTPUT) { + dmap = adev->dmap_out; + save_flags(flags); + cli(); + if (dmap->qlen > 0 && !(dmap->flags & DMA_ACTIVE)) + DMAbuf_launch_output(dev, dmap); + adev->dmap_out->flags |= DMA_SYNCING; + adev->dmap_out->underrun_count = 0; + while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs && + adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) { + dmabuf_set_timeout(dmap); + interruptible_sleep_on(&adev->out_sleeper); + if (!current->timeout) { + adev->dmap_out->flags &= ~DMA_SYNCING; + restore_flags(flags); + return adev->dmap_out->qlen; + } + current->timeout = 0; + } + adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); + restore_flags(flags); + + /* + * Some devices such as GUS have huge amount of on board RAM for the + * audio data. We have to wait until the device has finished playing. + */ + + save_flags(flags); + cli(); + if (adev->d->local_qlen) { /* Device has hidden buffers */ + while (!signal_pending(current) && adev->d->local_qlen(dev)) { + dmabuf_set_timeout(dmap); + interruptible_sleep_on(&adev->out_sleeper); + current->timeout = 0; + } + } + restore_flags(flags); + } + adev->dmap_out->dma_mode = DMODE_NONE; + return adev->dmap_out->qlen; } -int -DMAbuf_release(int dev, int mode) +int DMAbuf_release(int dev, int mode) { - unsigned long flags; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->closing = 1; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->closing = 1; + struct audio_operations *adev = audio_devs[dev]; + unsigned long flags; - if (audio_devs[dev]->open_mode & OPEN_WRITE) - if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)) - if (!signal_pending(current) - && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) - { - DMAbuf_sync(dev); - } - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset(audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } + if (adev->open_mode & OPEN_WRITE) + adev->dmap_out->closing = 1; + if (adev->open_mode & OPEN_READ) + adev->dmap_in->closing = 1; + + if (adev->open_mode & OPEN_WRITE) + if (!(adev->dmap_in->mapping_flags & DMA_MAP_MAPPED)) + if (!signal_pending(current) && (adev->dmap_out->dma_mode == DMODE_OUTPUT)) + DMAbuf_sync(dev); + if (adev->dmap_out->dma_mode == DMODE_OUTPUT) + memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->bytes_in_use); save_flags(flags); cli(); DMAbuf_reset(dev); - audio_devs[dev]->d->close(dev); - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + adev->d->close(dev); - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->open_mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - close_dmap(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); - audio_devs[dev]->open_mode = 0; + if (adev->open_mode & OPEN_WRITE) + close_dmap(adev, adev->dmap_out); + if (adev->open_mode == OPEN_READ || + (adev->open_mode != OPEN_WRITE && + adev->flags & DMA_DUPLEX)) + close_dmap(adev, adev->dmap_in); + adev->open_mode = 0; restore_flags(flags); - return 0; } -int -DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap) +int DMAbuf_activate_recording(int dev, struct dma_buffparms *dmap) { - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; + struct audio_operations *adev = audio_devs[dev]; + int err; - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) + if (!(adev->open_mode & OPEN_READ)) return 0; - - if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ - { - DMAbuf_sync(dev); - DMAbuf_reset(dev); - dmap->dma_mode = DMODE_NONE; - } - if (!dmap->dma_mode) - { - int err; - - reorganize_buffers(dev, dmap, 1); - if ((err = audio_devs[dev]->d->prepare_for_input(dev, - dmap->fragment_size, dmap->nbufs)) < 0) - { - return err; - } - dmap->dma_mode = DMODE_INPUT; - } - if (!(dmap->flags & DMA_ACTIVE)) - { - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0); - dmap->flags |= DMA_ACTIVE; - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } + if (!(adev->enable_bits & PCM_ENABLE_INPUT)) + return 0; + if (dmap->dma_mode == DMODE_OUTPUT) { /* Direction change */ + DMAbuf_sync(dev); + DMAbuf_reset(dev); + dmap->dma_mode = DMODE_NONE; + } + if (!dmap->dma_mode) { + reorganize_buffers(dev, dmap, 1); + if ((err = adev->d->prepare_for_input(dev, + dmap->fragment_size, dmap->nbufs)) < 0) + return err; + dmap->dma_mode = DMODE_INPUT; + } + if (!(dmap->flags & DMA_ACTIVE)) { + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); + adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 0); + dmap->flags |= DMA_ACTIVE; + if (adev->d->trigger) + adev->d->trigger(dev, adev->enable_bits * adev->go); + } return 0; } -int -DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) +int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) { - unsigned long flags; - int err = 0, n = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; + struct audio_operations *adev = audio_devs[dev]; + unsigned long flags; + int err = 0, n = 0; + struct dma_buffparms *dmap = adev->dmap_in; + int go; - if (!(audio_devs[dev]->open_mode & OPEN_READ)) + if (!(adev->open_mode & OPEN_READ)) return -EIO; if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); - save_flags(flags); cli(); - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) - { - printk("Sound: Can't read from mmapped device (1)\n"); + if (adev->dmap_in->mapping_flags & DMA_MAP_MAPPED) { +/* printk(KERN_WARNING "Sound: Can't read from mmapped device (1)\n");*/ restore_flags(flags); return -EINVAL; - } else - while (dmap->qlen <= 0 && n++ < 10) - { - int tmout; - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || - !audio_devs[dev]->go) - { - restore_flags(flags); - return -EAGAIN; - } - if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) - { - restore_flags(flags); - return err; - } - /* Wait for the next block */ - - if (dontblock) - { - restore_flags(flags); - return -EAGAIN; - } - if (!audio_devs[dev]->go) - tmout = 0; - else - { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - in_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&in_sleeper[dev]); - if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - in_sleep_flag[dev].opts |= WK_TIMEOUT; - } - in_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) - { - err = -EIO; - printk("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); - dma_reset_input(dev); - ; - } else - err = -EINTR; - } + } else while (dmap->qlen <= 0 && n++ < 10) { + if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) { + restore_flags(flags); + return -EAGAIN; + } + if ((err = DMAbuf_activate_recording(dev, dmap)) < 0) { + restore_flags(flags); + return err; + } + /* Wait for the next block */ + + if (dontblock) { + restore_flags(flags); + return -EAGAIN; + } + if (!(go = adev->go)) + current->timeout = 0; + else + dmabuf_set_timeout(dmap); + interruptible_sleep_on(&adev->in_sleeper); + if (go && !current->timeout) { + /* FIXME: include device name */ + err = -EIO; + printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); + dma_reset_input(dev); + } else + err = -EINTR; + current->timeout = 0; + } restore_flags(flags); if (dmap->qlen <= 0) - { - if (err == 0) - err = -EINTR; - return err; - } + return err ? err : -EINTR; *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; *len = dmap->fragment_size - dmap->counts[dmap->qhead]; return dmap->qhead; } -int -DMAbuf_rmchars(int dev, int buff_no, int c) +int DMAbuf_rmchars(int dev, int buff_no, int c) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - int p = dmap->counts[dmap->qhead] + c; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_in; + int p = dmap->counts[dmap->qhead] + c; if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk("Sound: Can't read from mmapped device (2)\n"); - return -EINVAL; - } else if (dmap->qlen <= 0) + { +/* printk("Sound: Can't read from mmapped device (2)\n");*/ + return -EINVAL; + } + else if (dmap->qlen <= 0) return -EIO; - else if (p >= dmap->fragment_size) - { /* This buffer is completely empty */ - dmap->counts[dmap->qhead] = 0; - dmap->qlen--; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - } else - dmap->counts[dmap->qhead] = p; + else if (p >= dmap->fragment_size) { /* This buffer is completely empty */ + dmap->counts[dmap->qhead] = 0; + dmap->qlen--; + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + } + else dmap->counts[dmap->qhead] = p; return 0; } -int -DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction) +int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction) { -/* - * Try to approximate the active byte position of the DMA pointer within the - * buffer area as well as possible. - */ - int pos; - unsigned long flags; + /* + * Try to approximate the active byte position of the DMA pointer within the + * buffer area as well as possible. + */ + + int pos; + unsigned long flags; save_flags(flags); cli(); if (!(dmap->flags & DMA_ACTIVE)) pos = 0; - else - { - int chan = dmap->dma; - - clear_dma_ff(chan); - disable_dma(dmap->dma); - pos = get_dma_residue(chan); - pos = dmap->bytes_in_use - pos; - - if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) - if (direction == DMODE_OUTPUT) - { - if (dmap->qhead == 0) - if (pos > dmap->fragment_size) - pos = 0; - } else - { - if (dmap->qtail == 0) - if (pos > dmap->fragment_size) - pos = 0; - } - if (pos < 0) - pos = 0; - if (pos >= dmap->bytes_in_use) - pos = 0; - enable_dma(dmap->dma); - } + else { + int chan = dmap->dma; + clear_dma_ff(chan); + disable_dma(dmap->dma); + pos = get_dma_residue(chan); + pos = dmap->bytes_in_use - pos; + + if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) { + if (direction == DMODE_OUTPUT) { + if (dmap->qhead == 0) + if (pos > dmap->fragment_size) + pos = 0; + } else { + if (dmap->qtail == 0) + if (pos > dmap->fragment_size) + pos = 0; + } + } + if (pos < 0) + pos = 0; + if (pos >= dmap->bytes_in_use) + pos = 0; + enable_dma(dmap->dma); + } restore_flags(flags); /* printk( "%04x ", pos); */ @@ -747,42 +642,37 @@ } /* - * DMAbuf_start_devices() is called by the /dev/music driver to start - * one or more audio devices at desired moment. + * DMAbuf_start_devices() is called by the /dev/music driver to start + * one or more audio devices at desired moment. */ -static void -DMAbuf_start_device(int dev) -{ - if (audio_devs[dev]->open_mode != 0) - if (!audio_devs[dev]->go) - { - /* OK to start the device */ - audio_devs[dev]->go = 1; - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } -} - -void -DMAbuf_start_devices(unsigned int devmask) +void DMAbuf_start_devices(unsigned int devmask) { - int dev; + struct audio_operations *adev; + int dev; - for (dev = 0; dev < num_audiodevs; dev++) - if ((devmask & (1 << dev)) && audio_devs[dev] != NULL) - DMAbuf_start_device(dev); + for (dev = 0; dev < num_audiodevs; dev++) { + if (!(devmask & (1 << dev))) + continue; + if (!(adev = audio_devs[dev])) + continue; + if (adev->open_mode == 0) + continue; + if (adev->go) + continue; + /* OK to start the device */ + adev->go = 1; + if (adev->d->trigger) + adev->d->trigger(dev,adev->enable_bits * adev->go); + } } -int -DMAbuf_space_in_queue(int dev) +int DMAbuf_space_in_queue(int dev) { - int len, max, tmp; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - int lim = dmap->nbufs; - + struct audio_operations *adev = audio_devs[dev]; + int len, max, tmp; + struct dma_buffparms *dmap = adev->dmap_out; + int lim = dmap->nbufs; if (lim < 2) lim = 2; @@ -791,8 +681,8 @@ return 0; /* - * Verify that there are no more pending buffers than the limit - * defined by the process. + * Verify that there are no more pending buffers than the limit + * defined by the process. */ max = dmap->max_fragments; @@ -800,15 +690,12 @@ max = lim; len = dmap->qlen; - if (audio_devs[dev]->d->local_qlen) - { - tmp = audio_devs[dev]->d->local_qlen(dev); - if (tmp && len) - tmp--; /* - * This buffer has been counted twice - */ - len += tmp; - } + if (adev->d->local_qlen) { + tmp = adev->d->local_qlen(dev); + if (tmp && len) + tmp--; /* This buffer has been counted twice */ + len += tmp; + } if (dmap->byte_counter % dmap->fragment_size) /* There is a partial fragment */ len = len + 1; @@ -817,87 +704,53 @@ return max - len; } -static int -output_sleep(int dev, int dontblock) +static int output_sleep(int dev, int dontblock) { - int tmout; - int err = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct audio_operations *adev = audio_devs[dev]; + int err = 0; + struct dma_buffparms *dmap = adev->dmap_out; + int timeout; if (dontblock) - { - return -EAGAIN; - } - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - { - return -EAGAIN; - } + return -EAGAIN; + if (!(adev->enable_bits & PCM_ENABLE_OUTPUT)) + return -EAGAIN; + /* * Wait for free space */ - if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT) - tmout = 0; - else - { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - if (signal_pending(current)) return -EIO; - - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on(&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - printk("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); - ; - dma_reset_output(dev); - } else if (signal_pending(current)) - { - err = -EINTR; - } + timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT)); + if (timeout) + dmabuf_set_timeout(dmap); + else + current->timeout = 0; + interruptible_sleep_on(&adev->out_sleeper); + if (timeout && !current->timeout) { + printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); + dma_reset_output(dev); + } else { + current->timeout = 0; + if (signal_pending(current)) + err = -EINTR; + } return err; } -static int -find_output_space(int dev, char **buf, int *size) +static int find_output_space(int dev, char **buf, int *size) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long flags; - unsigned long active_offs; - long len, offs; - int maxfrags; - int occupied_bytes = (dmap->user_counter % dmap->fragment_size); + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_out; + unsigned long flags; + unsigned long active_offs; + long len, offs; + int maxfrags; + int occupied_bytes = (dmap->user_counter % dmap->fragment_size); *buf = dmap->raw_buf; - if (!(maxfrags = DMAbuf_space_in_queue(dev)) && !occupied_bytes) - { - return 0; - } + return 0; save_flags(flags); cli(); @@ -912,260 +765,183 @@ #endif offs = (dmap->user_counter % dmap->bytes_in_use) & ~SAMPLE_ROUNDUP; - if (offs < 0 || offs >= dmap->bytes_in_use) - { - printk("OSS: Got unexpected offs %ld. Giving up.\n", offs); - printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); - return 0; - } + if (offs < 0 || offs >= dmap->bytes_in_use) { + printk(KERN_ERR "Sound: Got unexpected offs %ld. Giving up.\n", offs); + printk("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); + return 0; + } *buf = dmap->raw_buf + offs; len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */ if ((offs + len) > dmap->bytes_in_use) - { - len = dmap->bytes_in_use - offs; - } - if (len < 0) - { - restore_flags(flags); - return 0; - } + len = dmap->bytes_in_use - offs; + if (len < 0) { + restore_flags(flags); + return 0; + } if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) - { - len = (maxfrags * dmap->fragment_size) - occupied_bytes; - } + len = (maxfrags * dmap->fragment_size) - occupied_bytes; *size = len & ~SAMPLE_ROUNDUP; - restore_flags(flags); return (*size > 0); } -int -DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) +int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock) { - unsigned long flags; - int err = -EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct audio_operations *adev = audio_devs[dev]; + unsigned long flags; + int err = -EIO; + struct dma_buffparms *dmap = adev->dmap_out; if (dmap->needs_reorg) reorganize_buffers(dev, dmap, 0); - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk("Sound: Can't write to mmapped device (3)\n"); - return -EINVAL; - } - if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ - { - DMAbuf_reset(dev); - dmap->dma_mode = DMODE_NONE; - } + if (dmap->mapping_flags & DMA_MAP_MAPPED) { +/* printk(KERN_DEBUG "Sound: Can't write to mmapped device (3)\n");*/ + return -EINVAL; + } + if (dmap->dma_mode == DMODE_INPUT) { /* Direction change */ + DMAbuf_reset(dev); + dmap->dma_mode = DMODE_NONE; + } dmap->dma_mode = DMODE_OUTPUT; save_flags(flags); cli(); - - while (find_output_space(dev, buf, size) <= 0) - { - if ((err = output_sleep(dev, dontblock)) < 0) - { - restore_flags(flags); - return err; - } - } - + while (find_output_space(dev, buf, size) <= 0) { + if ((err = output_sleep(dev, dontblock)) < 0) { + restore_flags(flags); + return err; + } + } restore_flags(flags); return 0; } -int -DMAbuf_move_wrpointer(int dev, int l) +int DMAbuf_move_wrpointer(int dev, int l) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long ptr = (dmap->user_counter / dmap->fragment_size) - * dmap->fragment_size; - - unsigned long end_ptr, p; - int post = (dmap->flags & DMA_POST); - - ; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_out; + unsigned long ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; + unsigned long end_ptr, p; + int post = (dmap->flags & DMA_POST); dmap->flags &= ~DMA_POST; - dmap->cfrag = -1; - dmap->user_counter += l; dmap->flags |= DMA_DIRTY; - if (dmap->user_counter >= dmap->max_byte_counter) - { /* Wrap the byte counters */ - long decr = dmap->user_counter; - - dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->user_counter; - dmap->byte_counter -= decr; - } + if (dmap->byte_counter >= dmap->max_byte_counter) { + /* Wrap the byte counters */ + long decr = dmap->byte_counter; + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; p = (dmap->user_counter - 1) % dmap->bytes_in_use; dmap->neutral_byte = dmap->raw_buf[p]; /* Update the fragment based bookkeeping too */ - while (ptr < end_ptr) - { - dmap->counts[dmap->qtail] = dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - dmap->qlen++; - ptr += dmap->fragment_size; - } + while (ptr < end_ptr) { + dmap->counts[dmap->qtail] = dmap->fragment_size; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + dmap->qlen++; + ptr += dmap->fragment_size; + } dmap->counts[dmap->qtail] = dmap->user_counter - ptr; -/* - * Let the low level driver to perform some postprocessing to - * the written data. - */ - if (audio_devs[dev]->d->postprocess_write) - audio_devs[dev]->d->postprocess_write(dev); + /* + * Let the low level driver to perform some postprocessing to + * the written data. + */ + if (adev->d->postprocess_write) + adev->d->postprocess_write(dev); if (!(dmap->flags & DMA_ACTIVE)) - if (dmap->qlen > 1 || - (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) - { - DMAbuf_launch_output(dev, dmap); - }; + if (dmap->qlen > 1 || (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) + DMAbuf_launch_output(dev, dmap); return 0; } -int -DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) +int DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) { - int chan; - struct dma_buffparms *dmap; - - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; - if (dmap->raw_buf == NULL) - { - printk("sound: DMA buffer(1) == NULL\n"); - printk("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } - if (chan < 0) + if (dmap->raw_buf == NULL) { + printk(KERN_ERR "sound: DMA buffer(1) == NULL\n"); + printk("Device %d, chn=%s\n", dev, (dmap == adev->dmap_out) ? "out" : "in"); return 0; - - sound_start_dma(dev, dmap, chan, physaddr, count, dma_mode, 0); - + } + if (dmap->dma < 0) + return 0; + sound_start_dma(dmap, physaddr, count, dma_mode); return count; } -static int -local_start_dma(int dev, unsigned long physaddr, int count, int dma_mode) +static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode) { - int chan; - struct dma_buffparms *dmap; + struct dma_buffparms *dmap = (dma_mode == DMA_MODE_WRITE) ? adev->dmap_out : adev->dmap_in; - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { - printk("sound: DMA buffer(2) == NULL\n"); - printk("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } + if (dmap->raw_buf == NULL) { + printk(KERN_ERR "sound: DMA buffer(2) == NULL\n"); + printk(KERN_ERR "Device %s, chn=%s\n", adev->name, (dmap == adev->dmap_out) ? "out" : "in"); + return 0; + } if (dmap->flags & DMA_NODMA) - { - return 1; - } - if (chan < 0) + return 1; + if (dmap->dma < 0) return 0; - - sound_start_dma(dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1); + sound_start_dma(dmap, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode | DMA_AUTOINIT); dmap->flags |= DMA_STARTED; - return count; } -static void -finish_output_interrupt(int dev, struct dma_buffparms *dmap) +static void finish_output_interrupt(int dev, struct dma_buffparms *dmap) { - unsigned long flags; + struct audio_operations *adev = audio_devs[dev]; if (dmap->audio_callback != NULL) dmap->audio_callback(dev, dmap->callback_parm); - - save_flags(flags); - cli(); - if ((out_sleep_flag[dev].opts & WK_SLEEP)) - { - { - out_sleep_flag[dev].opts = WK_WAKEUP; - wake_up(&out_sleeper[dev]); - }; - } - restore_flags(flags); + wake_up(&adev->out_sleeper); } -static void -do_outputintr(int dev, int dummy) +static void do_outputintr(int dev, int dummy) { - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - int this_fragment; - -#ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_out->dma >= 0) - sound_dma_intr(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); -#endif + struct audio_operations *adev = audio_devs[dev]; + unsigned long flags; + struct dma_buffparms *dmap = adev->dmap_out; + int this_fragment; - if (dmap->raw_buf == NULL) - { - printk("Sound: Fatal error. Audio interrupt (%d) after freeing buffers.\n", dev); - return; - } - if (dmap->mapping_flags & DMA_MAP_MAPPED) /* Virtual memory mapped access */ - { - /* mmapped access */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - dmap->qlen++; /* Yes increment it (don't decrement) */ - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - dmap->counts[dmap->qhead] = dmap->fragment_size; - - DMAbuf_launch_output(dev, dmap); - finish_output_interrupt(dev, dmap); - return; - } + if (dmap->raw_buf == NULL) { + printk(KERN_ERR "Sound: Error. Audio interrupt (%d) after freeing buffers.\n", dev); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* Virtual memory mapped access */ + /* mmapped access */ + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + if (dmap->qhead == 0) { /* Wrapped */ + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ + long decr = dmap->byte_counter; + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + dmap->qlen++; /* Yes increment it (don't decrement) */ + if (!(adev->flags & DMA_AUTOMODE)) + dmap->flags &= ~DMA_ACTIVE; + dmap->counts[dmap->qhead] = dmap->fragment_size; + DMAbuf_launch_output(dev, dmap); + finish_output_interrupt(dev, dmap); + return; + } save_flags(flags); cli(); @@ -1173,395 +949,267 @@ this_fragment = dmap->qhead; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) + if (dmap->qhead == 0) { /* Wrapped */ + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ + long decr = dmap->byte_counter; + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use); + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + if (!(adev->flags & DMA_AUTOMODE)) dmap->flags &= ~DMA_ACTIVE; - - while (dmap->qlen <= 0) - { - dmap->underrun_count++; - - dmap->qlen++; - if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) - { - dmap->flags &= ~DMA_DIRTY; - memset(audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->buffsize); - } - dmap->user_counter += dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - + while (dmap->qlen <= 0) { + dmap->underrun_count++; + dmap->qlen++; + if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) { + dmap->flags &= ~DMA_DIRTY; + memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, + adev->dmap_out->buffsize); + } + dmap->user_counter += dmap->fragment_size; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + } if (dmap->qlen > 0) DMAbuf_launch_output(dev, dmap); - restore_flags(flags); finish_output_interrupt(dev, dmap); } -void -DMAbuf_outputintr(int dev, int notify_only) +void DMAbuf_outputintr(int dev, int notify_only) { - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + struct audio_operations *adev = audio_devs[dev]; + unsigned long flags; + struct dma_buffparms *dmap = adev->dmap_out; save_flags(flags); cli(); - - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; - - clear_dma_ff(chan); - disable_dma(dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue(chan); - enable_dma(dmap->dma); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - - n = 0; - while (dmap->qhead != pos && n++ < dmap->nbufs) - { - do_outputintr(dev, notify_only); - } - } else + if (!(dmap->flags & DMA_NODMA)) { + int chan = dmap->dma, pos, n; + clear_dma_ff(chan); + disable_dma(dmap->dma); + pos = dmap->bytes_in_use - get_dma_residue(chan); + enable_dma(dmap->dma); + pos = pos / dmap->fragment_size; /* Actual qhead */ + if (pos < 0 || pos >= dmap->nbufs) + pos = 0; + n = 0; + while (dmap->qhead != pos && n++ < dmap->nbufs) + do_outputintr(dev, notify_only); + } + else do_outputintr(dev, notify_only); restore_flags(flags); } -static void -do_inputintr(int dev) +static void do_inputintr(int dev) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_in; -#ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_in->dma >= 0) - sound_dma_intr(dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); -#endif - - if (dmap->raw_buf == NULL) - { - printk("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); - return; - } - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - dmap->qlen++; - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - { - if (dmap->needs_reorg) - reorganize_buffers(dev, dmap, 0); - local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - dmap->flags |= DMA_ACTIVE; - } else if (dmap->qlen >= (dmap->nbufs - 1)) - { - printk("Sound: Recording overrun\n"); - dmap->underrun_count++; - - /* Just throw away the oldest fragment but keep the engine running */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) - { - dmap->qlen++; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - } - if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - local_start_dma(dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input(dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger(dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } + if (dmap->raw_buf == NULL) { + printk(KERN_ERR "Sound: Fatal error. Audio interrupt after freeing buffers.\n"); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) { + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + if (dmap->qtail == 0) { /* Wrapped */ + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ + long decr = dmap->byte_counter; + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + dmap->qlen++; + + if (!(adev->flags & DMA_AUTOMODE)) { + if (dmap->needs_reorg) + reorganize_buffers(dev, dmap, 0); + local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use,DMA_MODE_READ); + adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1); + if (adev->d->trigger) + adev->d->trigger(dev, adev->enable_bits * adev->go); + } + dmap->flags |= DMA_ACTIVE; + } else if (dmap->qlen >= (dmap->nbufs - 1)) { + printk(KERN_WARNING "Sound: Recording overrun\n"); + dmap->underrun_count++; + + /* Just throw away the oldest fragment but keep the engine running */ + dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + } else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) { + dmap->qlen++; + dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; + if (dmap->qtail == 0) { /* Wrapped */ + dmap->byte_counter += dmap->bytes_in_use; + if (dmap->byte_counter >= dmap->max_byte_counter) { /* Overflow */ + long decr = dmap->byte_counter; + dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; + decr -= dmap->byte_counter; + dmap->user_counter -= decr; + } + } + } + if (!(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { + local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); + adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1); + if (adev->d->trigger) + adev->d->trigger(dev,adev->enable_bits * adev->go); + } dmap->flags |= DMA_ACTIVE; - - save_flags(flags); - cli(); if (dmap->qlen > 0) - if ((in_sleep_flag[dev].opts & WK_SLEEP)) - { - { - in_sleep_flag[dev].opts = WK_WAKEUP; - wake_up(&in_sleeper[dev]); - }; - } - restore_flags(flags); + wake_up(&adev->in_sleeper); } -void -DMAbuf_inputintr(int dev) +void DMAbuf_inputintr(int dev) { - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_in; + unsigned long flags; save_flags(flags); cli(); - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; - - clear_dma_ff(chan); - disable_dma(dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue(chan); - enable_dma(dmap->dma); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - - n = 0; - while (dmap->qtail != pos && ++n < dmap->nbufs) - { - do_inputintr(dev); - } + if (!(dmap->flags & DMA_NODMA)) { + int chan = dmap->dma, pos, n; + clear_dma_ff(chan); + disable_dma(dmap->dma); + pos = dmap->bytes_in_use - get_dma_residue(chan); + enable_dma(dmap->dma); + + pos = pos / dmap->fragment_size; /* Actual qhead */ + if (pos < 0 || pos >= dmap->nbufs) + pos = 0; + + n = 0; + while (dmap->qtail != pos && ++n < dmap->nbufs) + do_inputintr(dev); } else do_inputintr(dev); restore_flags(flags); } -int -DMAbuf_open_dma(int dev) +int DMAbuf_open_dma(int dev) { -/* - * NOTE! This routine opens only the primary DMA channel (output). - */ - - int chan = audio_devs[dev]->dmap_out->dma; - int err; + /* + * NOTE! This routine opens only the primary DMA channel (output). + */ + struct audio_operations *adev = audio_devs[dev]; + int err; - if ((err = open_dmap(dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0) - { - return -EBUSY; - } - dma_init_buffers(dev, audio_devs[dev]->dmap_out); - out_sleep_flag[dev].opts = WK_NONE; - audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; - audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize; - - if (chan >= 0) - { - unsigned long flags; - - save_flags(flags); - cli(); - disable_dma(audio_devs[dev]->dmap_out->dma); - clear_dma_ff(chan); - restore_flags(flags); - } + if ((err = open_dmap(adev, OPEN_READWRITE, adev->dmap_out)) < 0) + return -EBUSY; + dma_init_buffers(adev->dmap_out); + adev->dmap_out->flags |= DMA_ALLOC_DONE; + adev->dmap_out->fragment_size = adev->dmap_out->buffsize; + + if (adev->dmap_out->dma >= 0) { + unsigned long flags; + + save_flags(flags); + cli(); + clear_dma_ff(adev->dmap_out->dma); + disable_dma(adev->dmap_out->dma); + restore_flags(flags); + } return 0; } -void -DMAbuf_close_dma(int dev) +void DMAbuf_close_dma(int dev) { - close_dmap(dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); + close_dmap(audio_devs[dev], audio_devs[dev]->dmap_out); } -void -DMAbuf_init(int dev, int dma1, int dma2) +void DMAbuf_init(int dev, int dma1, int dma2) { + struct audio_operations *adev = audio_devs[dev]; /* - * NOTE! This routine could be called several times. + * NOTE! This routine could be called several times. */ - if (audio_devs[dev] && audio_devs[dev]->dmap_out == NULL) - { - if (audio_devs[dev]->d == NULL) - panic("OSS: audio_devs[%d]->d == NULL\n", dev); - - if (audio_devs[dev]->parent_dev) - { /* Use DMA map of the parent dev */ - int parent = audio_devs[dev]->parent_dev - 1; - - audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; - audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; - } else - { - audio_devs[dev]->dmap_out = - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_out->dma = dma1; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_in->dma = dma2; - } - } - } + if (adev && adev->dmap_out == NULL) { + if (adev->d == NULL) + panic("OSS: audio_devs[%d]->d == NULL\n", dev); + + if (adev->parent_dev) { /* Use DMA map of the parent dev */ + int parent = adev->parent_dev - 1; + adev->dmap_out = audio_devs[parent]->dmap_out; + adev->dmap_in = audio_devs[parent]->dmap_in; + } else { + adev->dmap_out = adev->dmap_in = &adev->dmaps[0]; + adev->dmap_out->dma = dma1; + if (adev->flags & DMA_DUPLEX) { + adev->dmap_in = &adev->dmaps[1]; + adev->dmap_in->dma = dma2; + } + } + } } -int -DMAbuf_select(int dev, struct fileinfo *file, int sel_type, poll_table * wait) +static unsigned int poll_input(struct file * file, int dev, poll_table *wait) { - struct dma_buffparms *dmap; - unsigned long flags; + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_in; - switch (sel_type) - { - case SEL_IN: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - - dmap = audio_devs[dev]->dmap_in; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags(flags); - cli(); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&in_sleeper[dev], wait); - restore_flags(flags); - return 0; - } - if (dmap->dma_mode != DMODE_INPUT) - { - if (dmap->dma_mode == DMODE_NONE && - audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && - !dmap->qlen && - audio_devs[dev]->go) - { - unsigned long flags; - - save_flags(flags); - cli(); - DMAbuf_activate_recording(dev, dmap); - restore_flags(flags); - } - return 0; - } - if (!dmap->qlen) - { - save_flags(flags); - cli(); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&in_sleeper[dev], wait); - restore_flags(flags); - return 0; - } - return 1; - break; - - case SEL_OUT: - dmap = audio_devs[dev]->dmap_out; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags(flags); - cli(); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&out_sleeper[dev], wait); - restore_flags(flags); - return 0; - } - if (dmap->dma_mode == DMODE_INPUT) - { - return 0; - } - if (dmap->dma_mode == DMODE_NONE) - { - return 1; - } - if (!DMAbuf_space_in_queue(dev)) - { - save_flags(flags); - cli(); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait(&out_sleeper[dev], wait); - restore_flags(flags); - return 0; - } - return 1; - break; - - case SEL_EX: - return 0; - } + 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; + } + if (dmap->dma_mode != DMODE_INPUT) { + if (dmap->dma_mode == DMODE_NONE && + adev->enable_bits & PCM_ENABLE_INPUT && + !dmap->qlen && adev->go) { + unsigned long flags; + + poll_wait(file, &adev->in_sleeper, wait); + save_flags(flags); + cli(); + DMAbuf_activate_recording(dev, dmap); + restore_flags(flags); + } + return 0; + } + poll_wait(file, &adev->in_sleeper, wait); + if (!dmap->qlen) + return 0; + return POLLIN | POLLRDNORM; +} - return 0; +static unsigned int poll_output(struct file * file, int dev, poll_table *wait) +{ + struct audio_operations *adev = audio_devs[dev]; + struct dma_buffparms *dmap = adev->dmap_out; + + 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)) + return 0; + return POLLOUT | POLLWRNORM; } -void -DMAbuf_deinit(int dev) +unsigned int DMAbuf_poll(struct file * file, int dev, poll_table *wait) { -/* This routine is called when driver is being unloaded */ -#ifdef RUNTIME_DMA_ALLOC - if (audio_devs[dev]) - sound_free_dmap (dev, audio_devs[dev]->dmap_out, - audio_devs[dev]->dmap_out->dma); - - if (audio_devs[dev] && audio_devs[dev]->flags & DMA_DUPLEX) - sound_free_dmap (dev, audio_devs[dev]->dmap_in, - audio_devs[dev]->dmap_in->dma); -#endif + return poll_input(file, dev, wait) | poll_output(file, dev, wait); } #endif diff -ur --new-file old/linux/drivers/sound/dmabuf.c.old new/linux/drivers/sound/dmabuf.c.old --- old/linux/drivers/sound/dmabuf.c.old Mon Dec 1 18:45:01 1997 +++ new/linux/drivers/sound/dmabuf.c.old Thu Jan 1 01:00:00 1970 @@ -1,1599 +0,0 @@ -/* - * sound/dmabuf.c - * - * The DMA buffer manager for digitized voice applications - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -#include - -#define BE_CONSERVATIVE - -#include "sound_config.h" - -#if defined(CONFIG_AUDIO) || defined(CONFIG_GUSHW) - -static struct wait_queue *in_sleeper[MAX_AUDIO_DEV] = -{NULL}; -static volatile struct snd_wait in_sleep_flag[MAX_AUDIO_DEV] = -{ - {0}}; -static struct wait_queue *out_sleeper[MAX_AUDIO_DEV] = -{NULL}; -static volatile struct snd_wait out_sleep_flag[MAX_AUDIO_DEV] = -{ - {0}}; - -static int ndmaps = 0; - -#define MAX_DMAP (MAX_AUDIO_DEV*2) - -static struct dma_buffparms dmaps[MAX_DMAP] = -{ - {0}}; - -static void dma_reset_output (int dev); -static void dma_reset_input (int dev); -static int local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); - -static void -dma_init_buffers (int dev, struct dma_buffparms *dmap) -{ - - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->bytes_in_use = dmap->buffsize; - - dmap->dma_mode = DMODE_NONE; - dmap->mapping_flags = 0; - dmap->neutral_byte = 0x80; - dmap->data_rate = 8000; - dmap->cfrag = -1; - dmap->closing = 0; - dmap->nbufs = 1; - dmap->flags = DMA_BUSY; /* Other flags off */ -} - -static int -open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan) -{ - if (dmap->flags & DMA_BUSY) - return -EBUSY; - - { - int err; - - if ((err = sound_alloc_dmap (dev, dmap, chan)) < 0) - return err; - } - - if (dmap->raw_buf == NULL) - { - printk ("Sound: DMA buffers not available\n"); - return -ENOSPC; /* Memory allocation failed during boot */ - } - - if (sound_open_dma (chan, audio_devs[dev]->name)) - { - printk ("Unable to grab(2) DMA%d for the audio driver\n", chan); - return -EBUSY; - } - - dma_init_buffers (dev, dmap); - dmap->open_mode = mode; - dmap->subdivision = dmap->underrun_count = 0; - dmap->fragment_size = 0; - dmap->max_fragments = 65536; /* Just a large value */ - dmap->byte_counter = 0; - dmap->max_byte_counter = 8000 * 60 * 60; - dmap->applic_profile = APF_NORMAL; - dmap->needs_reorg = 1; - dmap->audio_callback = NULL; - dmap->callback_parm = 0; - - - if (dmap->dma_mode & DMODE_OUTPUT) - { - out_sleep_flag[dev].opts = WK_NONE; - } - else - { - in_sleep_flag[dev].opts = WK_NONE; - } - - return 0; -} - -static void -close_dmap (int dev, struct dma_buffparms *dmap, int chan) -{ - sound_close_dma (chan); - - if (dmap->flags & DMA_BUSY) - dmap->dma_mode = DMODE_NONE; - dmap->flags &= ~DMA_BUSY; - - disable_dma (dmap->dma); -} - - -static unsigned int -default_set_bits (int dev, unsigned int bits) -{ - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) & bits); -} - -static int -default_set_speed (int dev, int speed) -{ - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) & speed); -} - -static short -default_set_channels (int dev, short channels) -{ - int c = channels; - - return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) & c); -} - -static void -check_driver (struct audio_driver *d) -{ - if (d->set_speed == NULL) - d->set_speed = default_set_speed; - if (d->set_bits == NULL) - d->set_bits = default_set_bits; - if (d->set_channels == NULL) - d->set_channels = default_set_channels; -} - -int -DMAbuf_open (int dev, int mode) -{ - int retval; - struct dma_buffparms *dmap_in = NULL; - struct dma_buffparms *dmap_out = NULL; - - if (dev >= num_audiodevs) - { - return -ENXIO; - } - - if (!audio_devs[dev]) - { - return -ENXIO; - } - - if (!(audio_devs[dev]->flags & DMA_DUPLEX)) - { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma; - } - - check_driver (audio_devs[dev]->d); - - if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0) - return retval; - - dmap_out = audio_devs[dev]->dmap_out; - dmap_in = audio_devs[dev]->dmap_in; - - if (dmap_in == dmap_out) - audio_devs[dev]->flags &= ~DMA_DUPLEX; - - if (mode & OPEN_WRITE) - { - if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmap_out->dma)) < 0) - { - audio_devs[dev]->d->close (dev); - return retval; - } - } - - audio_devs[dev]->enable_bits = mode; - - if (mode == OPEN_READ || (mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - { - if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmap_in->dma)) < 0) - { - audio_devs[dev]->d->close (dev); - - if (mode & OPEN_WRITE) - { - close_dmap (dev, dmap_out, audio_devs[dev]->dmap_out->dma); - } - - return retval; - } - } - - audio_devs[dev]->open_mode = mode; - audio_devs[dev]->go = 1; - - if (mode & OPEN_READ) - in_sleep_flag[dev].opts = WK_NONE; - - if (mode & OPEN_WRITE) - out_sleep_flag[dev].opts = WK_NONE; - - audio_devs[dev]->d->set_bits (dev, 8); - audio_devs[dev]->d->set_channels (dev, 1); - audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED); - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } - - return 0; -} - -void -DMAbuf_reset (int dev) -{ - if (audio_devs[dev]->open_mode & OPEN_WRITE) - dma_reset_output (dev); - - if (audio_devs[dev]->open_mode & OPEN_READ) - dma_reset_input (dev); -} - -static void -dma_reset_output (int dev) -{ - unsigned long flags; - int tmout; - - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - - if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ - return; - -/* - * First wait until the current fragment has been played completely - */ - save_flags (flags); - cli (); - - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - - audio_devs[dev]->dmap_out->underrun_count = 0; - if (!signal_pending(current) - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - -/* - * Finally shut the device off - */ - - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_output) - audio_devs[dev]->d->halt_io (dev); - else - audio_devs[dev]->d->halt_output (dev); - audio_devs[dev]->dmap_out->flags &= ~DMA_STARTED; - restore_flags (flags); - - clear_dma_ff (dmap->dma); - disable_dma (dmap->dma); - dmap->byte_counter = 0; - reorganize_buffers (dev, audio_devs[dev]->dmap_out, 0); - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; -} - -static void -dma_reset_input (int dev) -{ - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - save_flags (flags); - cli (); - if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->d->halt_input) - audio_devs[dev]->d->halt_io (dev); - else - audio_devs[dev]->d->halt_input (dev); - audio_devs[dev]->dmap_in->flags &= ~DMA_STARTED; - restore_flags (flags); - - dmap->qlen = dmap->qhead = dmap->qtail = dmap->user_counter = 0; - dmap->byte_counter = 0; - reorganize_buffers (dev, audio_devs[dev]->dmap_in, 1); -} - -void -DMAbuf_launch_output (int dev, struct dma_buffparms *dmap) -{ - if (!((audio_devs[dev]->enable_bits * audio_devs[dev]->go) & PCM_ENABLE_OUTPUT)) - return; /* Don't start DMA yet */ - - dmap->dma_mode = DMODE_OUTPUT; - - if (!(dmap->flags & DMA_ACTIVE) || !(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - if (!(dmap->flags & DMA_STARTED)) - { - reorganize_buffers (dev, dmap, 0); - - if (audio_devs[dev]->d->prepare_for_output (dev, - dmap->fragment_size, dmap->nbufs)) - return; - - if (!(dmap->flags & DMA_NODMA)) - { - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_WRITE); - } - dmap->flags |= DMA_STARTED; - } - if (dmap->counts[dmap->qhead] == 0) - dmap->counts[dmap->qhead] = dmap->fragment_size; - - dmap->dma_mode = DMODE_OUTPUT; - audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - dmap->flags |= DMA_ACTIVE; -} - -int -DMAbuf_sync (int dev) -{ - unsigned long flags; - int tmout, n = 0; - - if (!audio_devs[dev]->go && (!audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - return 0; - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - save_flags (flags); - cli (); - - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - - ; - if (dmap->qlen > 0) - if (!(dmap->flags & DMA_ACTIVE)) - DMAbuf_launch_output (dev, dmap); - ; - - audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; - - audio_devs[dev]->dmap_out->underrun_count = 0; - while (!signal_pending(current) - && n++ <= audio_devs[dev]->dmap_out->nbufs - && audio_devs[dev]->dmap_out->qlen - && audio_devs[dev]->dmap_out->underrun_count == 0) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; - restore_flags (flags); - return audio_devs[dev]->dmap_out->qlen; - } - } - audio_devs[dev]->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); - restore_flags (flags); - /* - * Some devices such as GUS have huge amount of on board RAM for the - * audio data. We have to wait until the device has finished playing. - */ - - save_flags (flags); - cli (); - if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ - { - while (!signal_pending(current) - && audio_devs[dev]->d->local_qlen (dev)) - { - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - } - } - restore_flags (flags); - } - audio_devs[dev]->dmap_out->dma_mode = DMODE_NONE; - return audio_devs[dev]->dmap_out->qlen; -} - -int -DMAbuf_release (int dev, int mode) -{ - unsigned long flags; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - audio_devs[dev]->dmap_out->closing = 1; - if (audio_devs[dev]->open_mode & OPEN_READ) - audio_devs[dev]->dmap_in->closing = 1; - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - if (!(audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED)) - if (!signal_pending(current) - && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) - { - DMAbuf_sync (dev); - } - - if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) - { - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); - } - - save_flags (flags); - cli (); - - DMAbuf_reset (dev); - audio_devs[dev]->d->close (dev); - - if (audio_devs[dev]->open_mode & OPEN_WRITE) - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); - - if (audio_devs[dev]->open_mode == OPEN_READ || - (audio_devs[dev]->open_mode != OPEN_WRITE && - audio_devs[dev]->flags & DMA_DUPLEX)) - close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); - audio_devs[dev]->open_mode = 0; - - restore_flags (flags); - - return 0; -} - -int -DMAbuf_activate_recording (int dev, struct dma_buffparms *dmap) -{ - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) - return 0; - - if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ - { - DMAbuf_sync (dev); - DMAbuf_reset (dev); - dmap->dma_mode = DMODE_NONE; - } - - if (!dmap->dma_mode) - { - int err; - - reorganize_buffers (dev, dmap, 1); - if ((err = audio_devs[dev]->d->prepare_for_input (dev, - dmap->fragment_size, dmap->nbufs)) < 0) - { - return err; - } - dmap->dma_mode = DMODE_INPUT; - } - - if (!(dmap->flags & DMA_ACTIVE)) - { - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0); - dmap->flags |= DMA_ACTIVE; - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - return 0; -} - -int -DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) -{ - unsigned long flags; - int err = 0, n = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return -EIO; - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - - save_flags (flags); - cli (); - if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't read from mmapped device (1)\n"); - restore_flags (flags); - return -EINVAL; - } - else - while (dmap->qlen <= 0 && n++ < 10) - { - int tmout; - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) || - !audio_devs[dev]->go) - { - restore_flags (flags); - return -EAGAIN; - } - - if ((err = DMAbuf_activate_recording (dev, dmap)) < 0) - { - restore_flags (flags); - return err; - } - - /* Wait for the next block */ - - if (dontblock) - { - restore_flags (flags); - return -EAGAIN; - } - - if (!audio_devs[dev]->go) - tmout = 0; - else - { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - in_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&in_sleeper[dev]); - if (!(in_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - in_sleep_flag[dev].opts |= WK_TIMEOUT; - } - in_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((in_sleep_flag[dev].opts & WK_TIMEOUT)) - { - err = -EIO; - printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); - dma_reset_input (dev); - ; - } - else - err = -EINTR; - } - restore_flags (flags); - - if (dmap->qlen <= 0) - { - if (err == 0) - err = -EINTR; - return err; - } - - *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; - *len = dmap->fragment_size - dmap->counts[dmap->qhead]; - - return dmap->qhead; -} - -int -DMAbuf_rmchars (int dev, int buff_no, int c) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - - int p = dmap->counts[dmap->qhead] + c; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't read from mmapped device (2)\n"); - return -EINVAL; - } - else if (dmap->qlen <= 0) - return -EIO; - else if (p >= dmap->fragment_size) - { /* This buffer is completely empty */ - dmap->counts[dmap->qhead] = 0; - dmap->qlen--; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - } - else - dmap->counts[dmap->qhead] = p; - - return 0; -} - -int -DMAbuf_get_buffer_pointer (int dev, struct dma_buffparms *dmap, int direction) -{ -/* - * Try to approximate the active byte position of the DMA pointer within the - * buffer area as well as possible. - */ - int pos; - unsigned long flags; - - save_flags (flags); - cli (); - if (!(dmap->flags & DMA_ACTIVE)) - pos = 0; - else - { - int chan = dmap->dma; - - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = get_dma_residue (chan); - pos = dmap->bytes_in_use - pos; - - if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) - if (direction == DMODE_OUTPUT) - { - if (dmap->qhead == 0) - if (pos > dmap->fragment_size) - pos = 0; - } - else - { - if (dmap->qtail == 0) - if (pos > dmap->fragment_size) - pos = 0; - } - - if (pos < 0) - pos = 0; - if (pos >= dmap->bytes_in_use) - pos = 0; - enable_dma (dmap->dma); - } - restore_flags (flags); - /* printk( "%04x ", pos); */ - - return pos; -} - -/* - * DMAbuf_start_devices() is called by the /dev/music driver to start - * one or more audio devices at desired moment. - */ -static void -DMAbuf_start_device (int dev) -{ - if (audio_devs[dev]->open_mode != 0) - if (!audio_devs[dev]->go) - { - /* OK to start the device */ - audio_devs[dev]->go = 1; - - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } -} - -void -DMAbuf_start_devices (unsigned int devmask) -{ - int dev; - - for (dev = 0; dev < num_audiodevs; dev++) - if (devmask & (1 << dev)) - DMAbuf_start_device (dev); -} - -int -DMAbuf_space_in_queue (int dev) -{ - int len, max, tmp; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - int lim = dmap->nbufs; - - - if (lim < 2) - lim = 2; - - if (dmap->qlen >= lim) /* No space at all */ - return 0; - - /* - * Verify that there are no more pending buffers than the limit - * defined by the process. - */ - - max = dmap->max_fragments; - if (max > lim) - max = lim; - len = dmap->qlen; - - if (audio_devs[dev]->d->local_qlen) - { - tmp = audio_devs[dev]->d->local_qlen (dev); - if (tmp && len) - tmp--; /* - * This buffer has been counted twice - */ - len += tmp; - } - if (dmap->byte_counter % dmap->fragment_size) /* There is a partial fragment */ - len = len + 1; - - if (len >= max) - return 0; - return max - len; -} - -static int -output_sleep (int dev, int dontblock) -{ - int tmout; - int err = 0; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dontblock) - { - return -EAGAIN; - } - - if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT)) - { - return -EAGAIN; - } - - /* - * Wait for free space - */ - if (!audio_devs[dev]->go || dmap->flags & DMA_NOTIMEOUT) - tmout = 0; - else - { - tmout = - (dmap->fragment_size * HZ) / dmap->data_rate; - - tmout += HZ / 5; /* Some safety distance */ - - if (tmout < (HZ / 2)) - tmout = HZ / 2; - if (tmout > 20 * HZ) - tmout = 20 * HZ; - } - - if (signal_pending(current)) - return -EIO; - - - { - unsigned long tlimit; - - if (tmout) - current->timeout = tlimit = jiffies + (tmout); - else - tlimit = (unsigned long) -1; - out_sleep_flag[dev].opts = WK_SLEEP; - interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - out_sleep_flag[dev].opts |= WK_TIMEOUT; - } - out_sleep_flag[dev].opts &= ~WK_SLEEP; - }; - if ((out_sleep_flag[dev].opts & WK_TIMEOUT)) - { - printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); - ; - dma_reset_output (dev); - } - else if (signal_pending(current)) - { - err = -EINTR; - } - - return err; -} - -static int -find_output_space (int dev, char **buf, int *size) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long flags; - unsigned long active_offs; - long len, offs; - int maxfrags; - int occupied_bytes = (dmap->user_counter % dmap->fragment_size); - - *buf = dmap->raw_buf; - - if (!(maxfrags = DMAbuf_space_in_queue (dev)) && !occupied_bytes) - { - return 0; - } - - save_flags (flags); - cli (); - -#ifdef BE_CONSERVATIVE - active_offs = dmap->byte_counter + dmap->qhead * dmap->fragment_size; -#else - active_offs = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); - /* Check for pointer wrapping situation */ - if (active_offs < 0 || active_offs >= dmap->bytes_in_use) - active_offs = 0; - active_offs += dmap->byte_counter; -#endif - - offs = (dmap->user_counter % dmap->bytes_in_use) & ~3; - if (offs < 0 || offs >= dmap->bytes_in_use) - { - printk ("OSS: Got unexpected offs %ld. Giving up.\n", offs); - printk ("Counter = %ld, bytes=%d\n", dmap->user_counter, dmap->bytes_in_use); - return 0; - } - *buf = dmap->raw_buf + offs; - - len = active_offs + dmap->bytes_in_use - dmap->user_counter; /* Number of unused bytes in buffer */ - - if ((offs + len) > dmap->bytes_in_use) - { - len = dmap->bytes_in_use - offs; - } - - if (len < 0) - { - restore_flags (flags); - return 0; - } - - if (len > ((maxfrags * dmap->fragment_size) - occupied_bytes)) - { - len = (maxfrags * dmap->fragment_size) - occupied_bytes; - } - - *size = len & ~3; - - restore_flags (flags); - return (len > 0); -} - -int -DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) -{ - unsigned long flags; - int err = -EIO; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - printk ("Sound: Can't write to mmapped device (3)\n"); - return -EINVAL; - } - - if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ - { - DMAbuf_reset (dev); - dmap->dma_mode = DMODE_NONE; - } - - dmap->dma_mode = DMODE_OUTPUT; - - save_flags (flags); - cli (); - - while (find_output_space (dev, buf, size) <= 0) - { - if ((err = output_sleep (dev, dontblock)) < 0) - { - restore_flags (flags); - return err; - } - } - - restore_flags (flags); - - return 0; -} - -int -DMAbuf_move_wrpointer (int dev, int l) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - unsigned long ptr = (dmap->user_counter / dmap->fragment_size) - * dmap->fragment_size; - - unsigned long end_ptr, p; - int post = (dmap->flags & DMA_POST); - - ; - - dmap->flags &= ~DMA_POST; - - dmap->cfrag = -1; - - dmap->user_counter += l; - dmap->flags |= DMA_DIRTY; - - if (dmap->user_counter >= dmap->max_byte_counter) - { /* Wrap the byte counters */ - long decr = dmap->user_counter; - - dmap->user_counter = (dmap->user_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->user_counter; - dmap->byte_counter -= decr; - } - - end_ptr = (dmap->user_counter / dmap->fragment_size) * dmap->fragment_size; - - p = (dmap->user_counter - 1) % dmap->bytes_in_use; - dmap->neutral_byte = dmap->raw_buf[p]; - - /* Update the fragment based bookkeeping too */ - while (ptr < end_ptr) - { - dmap->counts[dmap->qtail] = dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - dmap->qlen++; - ptr += dmap->fragment_size; - } - - dmap->counts[dmap->qtail] = dmap->user_counter - ptr; - -/* - * Let the low level driver to perform some postprocessing to - * the written data. - */ - if (audio_devs[dev]->d->postprocess_write) - audio_devs[dev]->d->postprocess_write (dev); - - if (!(dmap->flags & DMA_ACTIVE)) - if (dmap->qlen > 1 || - (dmap->qlen > 0 && (post || dmap->qlen >= dmap->nbufs - 1))) - { - DMAbuf_launch_output (dev, dmap); - } - - ; - return 0; -} - -int -DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) -{ - int chan; - struct dma_buffparms *dmap; - - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { - printk ("sound: DMA buffer(1) == NULL\n"); - printk ("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } - - if (chan < 0) - return 0; - - sound_start_dma (dev, dmap, chan, physaddr, count, dma_mode, 0); - - return count; -} - -static int -local_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) -{ - int chan; - struct dma_buffparms *dmap; - - if (dma_mode == DMA_MODE_WRITE) - { - chan = audio_devs[dev]->dmap_out->dma; - dmap = audio_devs[dev]->dmap_out; - } - else - { - chan = audio_devs[dev]->dmap_in->dma; - dmap = audio_devs[dev]->dmap_in; - } - - if (dmap->raw_buf == NULL) - { - printk ("sound: DMA buffer(2) == NULL\n"); - printk ("Device %d, chn=%s\n", dev, (dmap == audio_devs[dev]->dmap_out) ? "out" : "in"); - return 0; - } - - if (dmap->flags & DMA_NODMA) - { - return 1; - } - - if (chan < 0) - return 0; - - sound_start_dma (dev, dmap, chan, dmap->raw_buf_phys, dmap->bytes_in_use, dma_mode, 1); - dmap->flags |= DMA_STARTED; - - return count; -} - -static void -finish_output_interrupt (int dev, struct dma_buffparms *dmap) -{ - unsigned long flags; - - if (dmap->audio_callback != NULL) - dmap->audio_callback (dev, dmap->callback_parm); - - save_flags (flags); - cli (); - if ((out_sleep_flag[dev].opts & WK_SLEEP)) - { - { - out_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&out_sleeper[dev]); - }; - } - restore_flags (flags); -} - -static void -do_outputintr (int dev, int dummy) -{ - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - int this_fragment; - -#ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_out->dma >= 0) - sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); -#endif - - if (dmap->raw_buf == NULL) - { - printk ("Sound: Fatal error. Audio interrupt (%d) after freeing buffers.\n", dev); - return; - } - - if (dmap->mapping_flags & DMA_MAP_MAPPED) /* Virtual memory mapped access */ - { - /* mmapped access */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - - dmap->qlen++; /* Yes increment it (don't decrement) */ - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - dmap->counts[dmap->qhead] = dmap->fragment_size; - - DMAbuf_launch_output (dev, dmap); - finish_output_interrupt (dev, dmap); - return; - } - - save_flags (flags); - cli (); - - dmap->qlen--; - this_fragment = dmap->qhead; - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - - if (dmap->qhead == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - dmap->flags &= ~DMA_ACTIVE; - - while (dmap->qlen < 0) - { - dmap->underrun_count++; - - dmap->qlen++; - if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) - { - dmap->flags &= ~DMA_DIRTY; - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->buffsize); - } - dmap->user_counter += dmap->fragment_size; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - - if (dmap->qlen > 0) - DMAbuf_launch_output (dev, dmap); - - restore_flags (flags); - finish_output_interrupt (dev, dmap); -} - -void -DMAbuf_outputintr (int dev, int notify_only) -{ - unsigned long flags; - struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; - - save_flags (flags); - cli (); - - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; - - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue (chan); - enable_dma (dmap->dma); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - - n = 0; - while (dmap->qhead != pos && n++ < dmap->nbufs) - { - do_outputintr (dev, notify_only); - } - } - else - do_outputintr (dev, notify_only); - restore_flags (flags); -} - -static void -do_inputintr (int dev) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; - -#ifdef OS_DMA_INTR - if (audio_devs[dev]->dmap_in->dma >= 0) - sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmap_in->dma); -#endif - - if (dmap->raw_buf == NULL) - { - printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); - return; - } - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - dmap->qlen++; - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) - { - if (dmap->needs_reorg) - reorganize_buffers (dev, dmap, 0); - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - - dmap->flags |= DMA_ACTIVE; - } - else if (dmap->qlen >= (dmap->nbufs - 1)) - { - printk ("Sound: Recording overrun\n"); - dmap->underrun_count++; - - /* Just throw away the oldest fragment but keep the engine running */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - } - else if (dmap->qlen >= 0 && dmap->qlen < dmap->nbufs) - { - dmap->qlen++; - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - if (dmap->qtail == 0) /* Wrapped */ - { - dmap->byte_counter += dmap->bytes_in_use; - if (dmap->byte_counter >= dmap->max_byte_counter) /* Overflow */ - { - long decr = dmap->byte_counter; - - dmap->byte_counter = (dmap->byte_counter % dmap->bytes_in_use) + dmap->bytes_in_use; - decr -= dmap->byte_counter; - dmap->user_counter -= decr; - } - } - } - - if (!(audio_devs[dev]->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) - { - local_start_dma (dev, dmap->raw_buf_phys, dmap->bytes_in_use, - DMA_MODE_READ); - audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1); - if (audio_devs[dev]->d->trigger) - audio_devs[dev]->d->trigger (dev, - audio_devs[dev]->enable_bits * audio_devs[dev]->go); - } - - dmap->flags |= DMA_ACTIVE; - - save_flags (flags); - cli (); - if (dmap->qlen > 0) - if ((in_sleep_flag[dev].opts & WK_SLEEP)) - { - { - in_sleep_flag[dev].opts = WK_WAKEUP; - wake_up (&in_sleeper[dev]); - }; - } - restore_flags (flags); -} - -void -DMAbuf_inputintr (int dev) -{ - struct dma_buffparms *dmap = audio_devs[dev]->dmap_in; - unsigned long flags; - - save_flags (flags); - cli (); - - if (!(dmap->flags & DMA_NODMA)) - { - int chan = dmap->dma, pos, n; - - clear_dma_ff (chan); - disable_dma (dmap->dma); - pos = dmap->bytes_in_use - get_dma_residue (chan); - enable_dma (dmap->dma); - - pos = pos / dmap->fragment_size; /* Actual qhead */ - if (pos < 0 || pos >= dmap->nbufs) - pos = 0; - - n = 0; - while (dmap->qtail != pos && ++n < dmap->nbufs) - { - do_inputintr (dev); - } - } - else - do_inputintr (dev); - restore_flags (flags); -} - -int -DMAbuf_open_dma (int dev) -{ -/* - * NOTE! This routine opens only the primary DMA channel (output). - */ - - int chan = audio_devs[dev]->dmap_out->dma; - int err; - - if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, chan)) < 0) - { - return -EBUSY; - } - dma_init_buffers (dev, audio_devs[dev]->dmap_out); - out_sleep_flag[dev].opts = WK_NONE; - audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; - audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->dmap_out->buffsize; - - if (chan >= 0) - { - unsigned long flags; - - save_flags (flags); - cli (); - disable_dma (audio_devs[dev]->dmap_out->dma); - clear_dma_ff (chan); - restore_flags (flags); - } - - return 0; -} - -void -DMAbuf_close_dma (int dev) -{ - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmap_out->dma); -} - -void -DMAbuf_init (int dev, int dma1, int dma2) -{ - /* - * NOTE! This routine could be called several times. - */ - - if (audio_devs[dev]->dmap_out == NULL) - { - if (audio_devs[dev]->d == NULL) - panic ("OSS: audio_devs[%d]->d == NULL\n", dev); - - if (audio_devs[dev]->parent_dev) - { /* Use DMA map of the parent dev */ - int parent = audio_devs[dev]->parent_dev - 1; - - audio_devs[dev]->dmap_out = audio_devs[parent]->dmap_out; - audio_devs[dev]->dmap_in = audio_devs[parent]->dmap_in; - } - else - { - audio_devs[dev]->dmap_out = - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_out->dma = dma1; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - audio_devs[dev]->dmap_in = - &dmaps[ndmaps++]; - audio_devs[dev]->dmap_in->dma = dma2; - } - } - } -} - -int -DMAbuf_select (int dev, struct fileinfo *file, int sel_type, poll_table * wait) -{ - struct dma_buffparms *dmap; - unsigned long flags; - - switch (sel_type) - { - case SEL_IN: - if (!(audio_devs[dev]->open_mode & OPEN_READ)) - return 0; - - dmap = audio_devs[dev]->dmap_in; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags (flags); - cli (); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&in_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - - if (dmap->dma_mode != DMODE_INPUT) - { - if (dmap->dma_mode == DMODE_NONE && - audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT && - !dmap->qlen && - audio_devs[dev]->go) - { - unsigned long flags; - - save_flags (flags); - cli (); - DMAbuf_activate_recording (dev, dmap); - restore_flags (flags); - } - return 0; - } - - if (!dmap->qlen) - { - save_flags (flags); - cli (); - - in_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&in_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - return 1; - break; - - case SEL_OUT: - dmap = audio_devs[dev]->dmap_out; - - if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) - return 0; - - if (dmap->mapping_flags & DMA_MAP_MAPPED) - { - if (dmap->qlen) - return 1; - - save_flags (flags); - cli (); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&out_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - - if (dmap->dma_mode == DMODE_INPUT) - { - return 0; - } - - if (dmap->dma_mode == DMODE_NONE) - { - return 1; - } - - if (!DMAbuf_space_in_queue (dev)) - { - save_flags (flags); - cli (); - - out_sleep_flag[dev].opts = WK_SLEEP; - poll_wait (&out_sleeper[dev], wait); - restore_flags (flags); - return 0; - } - return 1; - break; - - case SEL_EX: - return 0; - } - - return 0; -} - - -#endif 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 Mon Dec 22 02:41:24 1997 +++ new/linux/drivers/sound/gus_card.c Thu Mar 12 19:52:09 1998 @@ -16,7 +16,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_GUSHW) || defined(MODULE) +#if defined(CONFIG_GUS) || defined(MODULE) #include "gus_hw.h" @@ -28,10 +28,9 @@ extern int have_gus_max; int gus_pnp_flag = 0; -void -attach_gus_card(struct address_info *hw_config) +void attach_gus_card(struct address_info *hw_config) { - snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp); + snd_set_irq_handler(hw_config->irq, gusintr, "Gravis Ultrasound", hw_config->osp, hw_config); gus_wave_init(hw_config); @@ -48,8 +47,7 @@ #endif } -int -probe_gus(struct address_info *hw_config) +int probe_gus(struct address_info *hw_config) { int irq; int io_addr; @@ -63,13 +61,13 @@ if (irq != 3 && irq != 5 && irq != 7 && irq != 9 && irq != 11 && irq != 12 && irq != 15) { - printk("GUS: Unsupported IRQ %d\n", irq); + printk(KERN_ERR "GUS: Unsupported IRQ %d\n", irq); return 0; } if (check_region(hw_config->io_base, 16)) - printk("GUS: I/O range conflict (1)\n"); + printk(KERN_ERR "GUS: I/O range conflict (1)\n"); else if (check_region(hw_config->io_base + 0x100, 16)) - printk("GUS: I/O range conflict (2)\n"); + printk(KERN_ERR "GUS: I/O range conflict (2)\n"); else if (gus_wave_detect(hw_config->io_base)) return 1; @@ -95,8 +93,7 @@ return 0; } -void -unload_gus(struct address_info *hw_config) +void unload_gus(struct address_info *hw_config) { DDB(printk("unload_gus(%x)\n", hw_config->io_base)); @@ -104,7 +101,7 @@ release_region(hw_config->io_base, 16); release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */ - snd_release_irq(hw_config->irq); + snd_release_irq(hw_config->irq, hw_config); sound_free_dma(hw_config->dma); @@ -112,72 +109,66 @@ sound_free_dma(hw_config->dma2); } -void -gusintr(int irq, void *dev_id, struct pt_regs *dummy) +void gusintr(int irq, void *dev_id, struct pt_regs *dummy) { - unsigned char src; - extern int gus_timer_enabled; + unsigned char src; + extern int gus_timer_enabled; + struct address_info *hw_config=dev_id; sti(); #ifdef CONFIG_GUSMAX if (have_gus_max) - adintr(irq, NULL, NULL); + adintr(irq, (void *)hw_config->slots[3], NULL); #endif while (1) - { - if (!(src = inb(u_IrqStatus))) - return; - - if (src & DMA_TC_IRQ) - { - guswave_dma_irq(); - } - if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) - { + { + if (!(src = inb(u_IrqStatus))) + return; + + if (src & DMA_TC_IRQ) + { + guswave_dma_irq(); + } + if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) + { #if defined(CONFIG_MIDI) - gus_midi_interrupt(0); + gus_midi_interrupt(0); #endif - } - if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) - { + } + if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) + { #if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE) - if (gus_timer_enabled) - { - sound_timer_interrupt(); - } - gus_write8(0x45, 0); /* Ack IRQ */ - gus_timer_command(4, 0x80); /* Reset IRQ flags */ - + if (gus_timer_enabled) + sound_timer_interrupt(); + gus_write8(0x45, 0); /* Ack IRQ */ + gus_timer_command(4, 0x80); /* Reset IRQ flags */ #else - gus_write8(0x45, 0); /* Stop timers */ + gus_write8(0x45, 0); /* Stop timers */ #endif - } - if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) - { - gus_voice_irq(); - } - } + } + if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) + gus_voice_irq(); + } } #endif /* - * Some extra code for the 16 bit sampling option + * Some extra code for the 16 bit sampling option */ + #ifdef CONFIG_GUS16 -int -probe_gus_db16(struct address_info *hw_config) +int probe_gus_db16(struct address_info *hw_config) { return ad1848_detect(hw_config->io_base, NULL, hw_config->osp); } -void -attach_gus_db16(struct address_info *hw_config) +void attach_gus_db16(struct address_info *hw_config) { -#if defined(CONFIG_GUSHW) || defined(MODULE) +#if defined(CONFIG_GUS) || defined(MODULE) gus_pcm_volume = 100; gus_wave_volume = 90; #endif @@ -189,8 +180,7 @@ hw_config->osp); } -void -unload_gus_db16(struct address_info *hw_config) +void unload_gus_db16(struct address_info *hw_config) { ad1848_unload(hw_config->io_base, @@ -226,16 +216,15 @@ MODULE_PARM(gus16, "i"); MODULE_PARM(db16, "i"); -int -init_module(void) +int init_module(void) { - printk("Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); if (io == -1 || dma == -1 || irq == -1) - { - printk("I/O, IRQ, and DMA are mandatory\n"); - return -EINVAL; - } + { + printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n"); + return -EINVAL; + } config.io_base = io; config.irq = irq; config.dma = dma; @@ -244,10 +233,10 @@ #if defined(CONFIG_GUS16) if (probe_gus_db16(&config) && gus16) - { - attach_gus_db16(&config); - db16 = 1; - } + { + attach_gus_db16(&config); + db16 = 1; + } #endif if (probe_gus(&config) == 0) return -ENODEV; @@ -256,8 +245,7 @@ return 0; } -void -cleanup_module(void) +void cleanup_module(void) { #if defined(CONFIG_GUS16) if (db16) diff -ur --new-file old/linux/drivers/sound/gus_midi.c new/linux/drivers/sound/gus_midi.c --- old/linux/drivers/sound/gus_midi.c Tue Dec 30 19:59:17 1997 +++ new/linux/drivers/sound/gus_midi.c Thu Feb 19 23:46:14 1998 @@ -17,7 +17,7 @@ #include "gus_hw.h" -#if ( defined(CONFIG_GUSHW) && defined(CONFIG_MIDI) ) || defined (MODULE) +#if ( defined(CONFIG_GUS) && defined(CONFIG_MIDI) ) || defined (MODULE) static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -33,24 +33,18 @@ extern int gus_base, gus_irq, gus_dma; extern int *gus_osp; -static int -GUS_MIDI_STATUS(void) +static int GUS_MIDI_STATUS(void) { return inb(u_MidiStatus); } -static int -gus_midi_open(int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) +static int gus_midi_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev)) { - if (midi_busy) - { - printk("GUS: Midi busy\n"); - return -EBUSY; - } + { +/* printk("GUS: Midi busy\n");*/ + return -EBUSY; + } outb((MIDI_RESET), u_MidiControl); gus_delay(); @@ -59,10 +53,10 @@ if (mode == OPEN_READ || mode == OPEN_READWRITE) if (!gus_pnp_flag) - { - gus_midi_control |= MIDI_ENABLE_RCV; - input_opened = 1; - } + { + gus_midi_control |= MIDI_ENABLE_RCV; + input_opened = 1; + } outb((gus_midi_control), u_MidiControl); /* Enable */ midi_busy = 1; @@ -72,8 +66,7 @@ return 0; } -static int -dump_to_midi(unsigned char midi_byte) +static int dump_to_midi(unsigned char midi_byte) { unsigned long flags; int ok = 0; @@ -84,24 +77,24 @@ cli(); if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY) - { - ok = 1; - outb((midi_byte), u_MidiData); - } else - { - /* - * Enable Midi xmit interrupts (again) - */ - gus_midi_control |= MIDI_ENABLE_XMIT; - outb((gus_midi_control), u_MidiControl); - } + { + ok = 1; + outb((midi_byte), u_MidiData); + } + else + { + /* + * Enable Midi xmit interrupts (again) + */ + gus_midi_control |= MIDI_ENABLE_XMIT; + outb((gus_midi_control), u_MidiControl); + } restore_flags(flags); return ok; } -static void -gus_midi_close(int dev) +static void gus_midi_close(int dev) { /* * Reset FIFO pointers, disable intrs @@ -111,10 +104,8 @@ midi_busy = 0; } -static int -gus_midi_out(int dev, unsigned char midi_byte) +static int gus_midi_out(int dev, unsigned char midi_byte) { - unsigned long flags; /* @@ -125,15 +116,14 @@ cli(); while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - + { + qlen--; + qhead++; + } restore_flags(flags); /* - * Output the byte if the local queue is empty. + * Output the byte if the local queue is empty. */ if (!qlen) @@ -143,14 +133,13 @@ */ /* - * Put to the local queue + * Put to the local queue */ if (qlen >= 256) return 0; /* * Local queue full */ - save_flags(flags); cli(); @@ -159,29 +148,24 @@ qtail++; restore_flags(flags); - return 1; } -static int -gus_midi_start_read(int dev) +static int gus_midi_start_read(int dev) { return 0; } -static int -gus_midi_end_read(int dev) +static int gus_midi_end_read(int dev) { return 0; } -static void -gus_midi_kick(int dev) +static void gus_midi_kick(int dev) { } -static int -gus_midi_buffer_status(int dev) +static int gus_midi_buffer_status(int dev) { unsigned long flags; @@ -192,12 +176,11 @@ cli(); if (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } + { + qlen--; + qhead++; + } restore_flags(flags); - return (qlen > 0) | !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY); } @@ -207,7 +190,9 @@ static struct midi_operations gus_midi_operations = { - {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS}, + { + "Gravis UltraSound Midi", 0, 0, SNDCARD_GUS + }, &std_midi_synth, {0}, gus_midi_open, @@ -224,16 +209,15 @@ NULL }; -void -gus_midi_init(struct address_info *hw_config) +void gus_midi_init(struct address_info *hw_config) { - int dev = sound_alloc_mididev(); + int dev = sound_alloc_mididev(); if (dev == -1) - { - printk(KERN_INFO "gus_midi: Too many midi devices detected\n"); - return; - } + { + printk(KERN_INFO "gus_midi: Too many midi devices detected\n"); + return; + } outb((MIDI_RESET), u_MidiControl); std_midi_synth.midi_dev = my_dev = dev; @@ -243,44 +227,41 @@ return; } -void -gus_midi_interrupt(int dummy) +void gus_midi_interrupt(int dummy) { volatile unsigned char stat, data; - unsigned long flags; - int timeout = 10; + unsigned long flags; + int timeout = 10; save_flags(flags); cli(); while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY)) - { - if (stat & MIDI_RCV_FULL) - { - data = inb(u_MidiData); - if (input_opened) - midi_input_intr(my_dev, data); - } - if (stat & MIDI_XMIT_EMPTY) - { - while (qlen && dump_to_midi(tmp_queue[qhead])) - { - qlen--; - qhead++; - } - - if (!qlen) - { - /* - * Disable Midi output interrupts, since no data in the buffer - */ - gus_midi_control &= ~MIDI_ENABLE_XMIT; - outb((gus_midi_control), u_MidiControl); - outb((gus_midi_control), u_MidiControl); - } - } - } - + { + if (stat & MIDI_RCV_FULL) + { + data = inb(u_MidiData); + if (input_opened) + midi_input_intr(my_dev, data); + } + if (stat & MIDI_XMIT_EMPTY) + { + while (qlen && dump_to_midi(tmp_queue[qhead])) + { + qlen--; + qhead++; + } + if (!qlen) + { + /* + * Disable Midi output interrupts, since no data in the buffer + */ + gus_midi_control &= ~MIDI_ENABLE_XMIT; + outb((gus_midi_control), u_MidiControl); + outb((gus_midi_control), u_MidiControl); + } + } + } restore_flags(flags); } diff -ur --new-file old/linux/drivers/sound/gus_vol.c new/linux/drivers/sound/gus_vol.c --- old/linux/drivers/sound/gus_vol.c Sat Nov 29 19:33:20 1997 +++ new/linux/drivers/sound/gus_vol.c Thu Feb 19 23:46:14 1998 @@ -12,7 +12,7 @@ #include #include "sound_config.h" -#if defined(CONFIG_GUSHW) || defined(MODULE) +#if defined(CONFIG_GUS) || defined(MODULE) #include "gus_linearvol.h" #define GUS_VOLUME gus_wave_volume @@ -34,10 +34,10 @@ * we can give a big boost to very weak voices like nylon guitar and the * basses. The normal value is 64. Strings are assigned lower values. */ -unsigned short -gus_adagio_vol(int vel, int mainv, int xpn, int voicev) + +unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev) { - int i, m, n, x; + int i, m, n, x; /* @@ -50,6 +50,7 @@ /* * Boost expression by voice volume above neutral. */ + if (voicev > 65) xpn += voicev - 64; xpn += (voicev - 64) / 2; @@ -85,18 +86,22 @@ * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit * mantissa m. */ + n = x; i = 7; if (n < 128) - { + { while (i > 0 && n < (1 << i)) i--; - } else + } + else + { while (n > 255) - { + { n >>= 1; i++; - } + } + } /* * Mantissa is part of linear volume not expressed in exponent. (This is * not quite like real logs -- I wonder if it's right.) @@ -107,12 +112,12 @@ * Adjust mantissa to 8 bits. */ if (m > 0) - { - if (i > 8) - m >>= i - 8; - else if (i < 8) - m <<= 8 - i; - } + { + if (i > 8) + m >>= i - 8; + else if (i < 8) + m <<= 8 - i; + } return ((i << 8) + m); } @@ -122,10 +127,9 @@ * and the volume set by the mixer-device (default 60%). */ -unsigned short -gus_linear_vol(int vol, int mainvol) +unsigned short gus_linear_vol(int vol, int mainvol) { - int mixer_mainvol; + int mixer_mainvol; if (vol <= 0) vol = 0; @@ -146,7 +150,6 @@ #else mainvol = 127; #endif - return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100]; } diff -ur --new-file old/linux/drivers/sound/gus_wave.c new/linux/drivers/sound/gus_wave.c --- old/linux/drivers/sound/gus_wave.c Mon Jan 5 22:37:03 1998 +++ new/linux/drivers/sound/gus_wave.c Thu Feb 19 23:46:14 1998 @@ -22,7 +22,7 @@ #include #include "gus_hw.h" -#if defined(CONFIG_GUSHW) || defined(MODULE) +#if defined(CONFIG_GUS) || defined(MODULE) #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) @@ -32,42 +32,42 @@ #define NOT_SAMPLE 0xffff struct voice_info - { - unsigned long orig_freq; - unsigned long current_freq; - unsigned long mode; - int fixed_pitch; - int bender; - int bender_range; - int panning; - int midi_volume; - unsigned int initial_volume; - unsigned int current_volume; - int loop_irq_mode, loop_irq_parm; +{ + unsigned long orig_freq; + unsigned long current_freq; + unsigned long mode; + int fixed_pitch; + int bender; + int bender_range; + int panning; + int midi_volume; + unsigned int initial_volume; + unsigned int current_volume; + int loop_irq_mode, loop_irq_parm; #define LMODE_FINISH 1 #define LMODE_PCM 2 #define LMODE_PCM_STOP 3 - int volume_irq_mode, volume_irq_parm; + int volume_irq_mode, volume_irq_parm; #define VMODE_HALT 1 #define VMODE_ENVELOPE 2 #define VMODE_START_NOTE 3 - int env_phase; - unsigned char env_rate[6]; - unsigned char env_offset[6]; - - /* - * Volume computation parameters for gus_adagio_vol() - */ - int main_vol, expression_vol, patch_vol; - - /* Variables for "Ultraclick" removal */ - int dev_pending, note_pending, volume_pending, - sample_pending; - char kill_pending; - long offset_pending; + int env_phase; + unsigned char env_rate[6]; + unsigned char env_offset[6]; + + /* + * Volume computation parameters for gus_adagio_vol() + */ + int main_vol, expression_vol, patch_vol; + + /* Variables for "Ultraclick" removal */ + int dev_pending, note_pending, volume_pending, + sample_pending; + char kill_pending; + long offset_pending; - }; +}; static struct voice_alloc_info *voice_alloc; @@ -101,6 +101,7 @@ * Current version of this driver doesn't allow synth and PCM functions * at the same time. The active_device specifies the active driver */ + static int active_device = 0; #define GUS_DEV_WAVE 1 /* Wave table synth */ @@ -114,12 +115,11 @@ static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */ static struct wait_queue *dram_sleeper = NULL; -static volatile struct snd_wait dram_sleep_flag = -{0}; /* * Variables and buffers for PCM output */ + #define MAX_PCM_BUFFERS (128*MAX_REALTIME_FACTOR) /* Don't change */ static int pcm_bsize, pcm_nblk, pcm_banksize; @@ -172,8 +172,10 @@ static int patch_table[MAX_PATCH]; static int patch_map[32]; -static struct synth_info gus_info = -{"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH}; +static struct synth_info gus_info = { + "Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, + 0, 16, 0, MAX_PATCH +}; static void gus_poke(long addr, unsigned char data); static void compute_and_set_volume(int voice, int volume, int ramp_time); @@ -187,10 +189,9 @@ #define INSTANT_RAMP -1 /* Instant change. No ramping */ #define FAST_RAMP 0 /* Fastest possible ramp */ -static void -reset_sample_memory(void) +static void reset_sample_memory(void) { - int i; + int i; for (i = 0; i <= MAX_SAMPLE; i++) sample_ptrs[i] = -1; @@ -209,17 +210,15 @@ patch_table[i] = NOT_SAMPLE; } -void -gus_delay(void) +void gus_delay(void) { - int i; + int i; for (i = 0; i < 7; i++) inb(u_DRAMIO); } -static void -gus_poke(long addr, unsigned char data) +static void gus_poke(long addr, unsigned char data) { /* Writes a byte to the DRAM */ unsigned long flags; @@ -235,8 +234,7 @@ restore_flags(flags); } -static unsigned char -gus_peek(long addr) +static unsigned char gus_peek(long addr) { /* Reads a byte from the DRAM */ unsigned long flags; unsigned char tmp; @@ -255,8 +253,7 @@ return tmp; } -void -gus_write8(int reg, unsigned int data) +void gus_write8(int reg, unsigned int data) { /* Writes to an indirect register (8 bit) */ unsigned long flags; @@ -269,9 +266,9 @@ restore_flags(flags); } -static unsigned char -gus_read8(int reg) -{ /* Reads from an indirect register (8 bit). Offset 0x80. */ +static unsigned char gus_read8(int reg) +{ + /* Reads from an indirect register (8 bit). Offset 0x80. */ unsigned long flags; unsigned char val; @@ -284,9 +281,9 @@ return val; } -static unsigned char -gus_look8(int reg) -{ /* Reads from an indirect register (8 bit). No additional offset. */ +static unsigned char gus_look8(int reg) +{ + /* Reads from an indirect register (8 bit). No additional offset. */ unsigned long flags; unsigned char val; @@ -299,9 +296,9 @@ return val; } -static void -gus_write16(int reg, unsigned int data) -{ /* Writes to an indirect register (16 bit) */ +static void gus_write16(int reg, unsigned int data) +{ + /* Writes to an indirect register (16 bit) */ unsigned long flags; save_flags(flags); @@ -315,9 +312,9 @@ restore_flags(flags); } -static unsigned short -gus_read16(int reg) -{ /* Reads from an indirect register (16 bit). Offset 0x80. */ +static unsigned short gus_read16(int reg) +{ + /* Reads from an indirect register (16 bit). Offset 0x80. */ unsigned long flags; unsigned char hi, lo; @@ -334,9 +331,9 @@ return ((hi << 8) & 0xff00) | lo; } -static unsigned short -gus_look16(int reg) -{ /* Reads from an indirect register (16 bit). No additional offset. */ +static unsigned short gus_look16(int reg) +{ + /* Reads from an indirect register (16 bit). No additional offset. */ unsigned long flags; unsigned char hi, lo; @@ -353,32 +350,33 @@ return ((hi << 8) & 0xff00) | lo; } -static void -gus_write_addr(int reg, unsigned long address, int frac, int is16bit) -{ /* Writes an 24 bit memory address */ +static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit) +{ + /* Writes an 24 bit memory address */ unsigned long hold_address; unsigned long flags; save_flags(flags); cli(); if (is16bit) - { - if (iw_mode) - { - /* Interwave spesific address translations */ - address >>= 1; - } else - { - /* - * Special processing required for 16 bit patches - */ - - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - } + { + if (iw_mode) + { + /* Interwave spesific address translations */ + address >>= 1; + } + else + { + /* + * Special processing required for 16 bit patches + */ + + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + } gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff)); gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff) + (frac << 5)); @@ -390,17 +388,14 @@ restore_flags(flags); } -static void -gus_select_voice(int voice) +static void gus_select_voice(int voice) { if (voice < 0 || voice > 31) return; - outb((voice), u_Voice); } -static void -gus_select_max_voices(int nvoices) +static void gus_select_max_voices(int nvoices) { if (iw_mode) nvoices = 32; @@ -410,26 +405,22 @@ nvoices = 32; voice_alloc->max_voice = nr_voices = nvoices; - gus_write8(0x0e, (nvoices - 1) | 0xc0); } -static void -gus_voice_on(unsigned int mode) +static void gus_voice_on(unsigned int mode) { gus_write8(0x00, (unsigned char) (mode & 0xfc)); gus_delay(); gus_write8(0x00, (unsigned char) (mode & 0xfc)); } -static void -gus_voice_off(void) +static void gus_voice_off(void) { gus_write8(0x00, gus_read8(0x00) | 0x03); } -static void -gus_voice_mode(unsigned int m) +static void gus_voice_mode(unsigned int m) { unsigned char mode = (unsigned char) (m & 0xff); @@ -439,8 +430,7 @@ gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc)); } -static void -gus_voice_freq(unsigned long freq) +static void gus_voice_freq(unsigned long freq) { unsigned long divisor = freq_div_table[nr_voices - 14]; unsigned short fc; @@ -455,34 +445,29 @@ gus_write16(0x01, fc); } -static void -gus_voice_volume(unsigned int vol) +static void gus_voice_volume(unsigned int vol) { gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */ gus_write16(0x09, (unsigned short) (vol << 4)); } -static void -gus_voice_balance(unsigned int balance) +static void gus_voice_balance(unsigned int balance) { gus_write8(0x0c, (unsigned char) (balance & 0xff)); } -static void -gus_ramp_range(unsigned int low, unsigned int high) +static void gus_ramp_range(unsigned int low, unsigned int high) { gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff)); gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff)); } -static void -gus_ramp_rate(unsigned int scale, unsigned int rate) +static void gus_ramp_rate(unsigned int scale, unsigned int rate) { gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); } -static void -gus_rampon(unsigned int m) +static void gus_rampon(unsigned int m) { unsigned char mode = (unsigned char) (m & 0xff); @@ -491,10 +476,9 @@ gus_write8(0x0d, mode & 0xfc); } -static void -gus_ramp_mode(unsigned int m) +static void gus_ramp_mode(unsigned int m) { - unsigned char mode = (unsigned char) (m & 0xff); + unsigned char mode = (unsigned char) (m & 0xff); gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc)); /* Leave the last 2 bits alone */ @@ -502,16 +486,14 @@ gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc)); } -static void -gus_rampoff(void) +static void gus_rampoff(void) { gus_write8(0x0d, 0x03); } -static void -gus_set_voice_pos(int voice, long position) +static void gus_set_voice_pos(int voice, long position) { - int sample_no; + int sample_no; if ((sample_no = sample_map[voice]) != -1) if (position < samples[sample_no].len) @@ -522,8 +504,7 @@ samples[sample_no].mode & WAVE_16_BITS); } -static void -gus_voice_init(int voice) +static void gus_voice_init(int voice) { unsigned long flags; @@ -541,8 +522,7 @@ } -static void -gus_voice_init2(int voice) +static void gus_voice_init2(int voice) { voices[voice].panning = 0; voices[voice].mode = 0; @@ -564,30 +544,30 @@ voices[voice].fixed_pitch = 0; } -static void -step_envelope(int voice) +static void step_envelope(int voice) { unsigned vol, prev_vol, phase; unsigned char rate; long int flags; if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) - { - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_rampoff(); - restore_flags(flags); - return; - /* - * Sustain phase begins. Continue envelope after receiving note off. - */ - } + { + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + restore_flags(flags); + return; + /* + * Sustain phase begins. Continue envelope after receiving note off. + */ + } if (voices[voice].env_phase >= 5) - { /* Envelope finished. Shoot the voice down */ - gus_voice_init(voice); - return; - } + { + /* Envelope finished. Shoot the voice down */ + gus_voice_init(voice); + return; + } prev_vol = voices[voice].current_volume; phase = ++voices[voice].env_phase; compute_volume(voice, voices[voice].midi_volume); @@ -606,30 +586,30 @@ voices[voice].volume_irq_mode = VMODE_ENVELOPE; if (((vol - prev_vol) / 64) == 0) /* No significant volume change */ - { - restore_flags(flags); - step_envelope(voice); /* Continue the envelope on the next step */ - return; - } + { + restore_flags(flags); + step_envelope(voice); /* Continue the envelope on the next step */ + return; + } if (vol > prev_vol) - { - if (vol >= (4096 - 64)) - vol = 4096 - 65; - gus_ramp_range(0, vol); - gus_rampon(0x20); /* Increasing volume, with IRQ */ - } else - { - if (vol <= 64) - vol = 65; - gus_ramp_range(vol, 4030); - gus_rampon(0x60); /* Decreasing volume, with IRQ */ - } + { + if (vol >= (4096 - 64)) + vol = 4096 - 65; + gus_ramp_range(0, vol); + gus_rampon(0x20); /* Increasing volume, with IRQ */ + } + else + { + if (vol <= 64) + vol = 65; + gus_ramp_range(vol, 4030); + gus_rampon(0x60); /* Decreasing volume, with IRQ */ + } voices[voice].current_volume = vol; restore_flags(flags); } -static void -init_envelope(int voice) +static void init_envelope(int voice) { voices[voice].env_phase = -1; voices[voice].current_volume = 64; @@ -637,17 +617,15 @@ step_envelope(voice); } -static void -start_release(int voice, long int flags) +static void start_release(int voice, long int flags) { if (gus_read8(0x00) & 0x03) return; /* Voice already stopped */ voices[voice].env_phase = 2; /* Will be incremented by step_envelope */ - voices[voice].current_volume = - voices[voice].initial_volume = - gus_read16(0x09) >> 4; /* Get current volume */ + voices[voice].current_volume = voices[voice].initial_volume = + gus_read16(0x09) >> 4; /* Get current volume */ voices[voice].mode &= ~WAVE_SUSTAIN_ON; gus_rampoff(); @@ -655,42 +633,41 @@ step_envelope(voice); } -static void -gus_voice_fade(int voice) +static void gus_voice_fade(int voice) { - int instr_no = sample_map[voice], is16bits; - long int flags; + int instr_no = sample_map[voice], is16bits; + long int flags; save_flags(flags); cli(); gus_select_voice(voice); if (instr_no < 0 || instr_no > MAX_SAMPLE) - { - gus_write8(0x00, 0x03); /* Hard stop */ - voice_alloc->map[voice] = 0; - restore_flags(flags); - return; - } + { + gus_write8(0x00, 0x03); /* Hard stop */ + voice_alloc->map[voice] = 0; + restore_flags(flags); + return; + } is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */ if (voices[voice].mode & WAVE_ENVELOPES) - { - start_release(voice, flags); - restore_flags(flags); - return; - } + { + start_release(voice, flags); + restore_flags(flags); + return; + } /* * Ramp the volume down but not too quickly. */ if ((int) (gus_read16(0x09) >> 4) < 100) /* Get current volume */ - { - gus_voice_off(); - gus_rampoff(); - gus_voice_init(voice); - restore_flags(flags); - return; - } + { + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + restore_flags(flags); + return; + } gus_ramp_range(65, 4030); gus_ramp_rate(2, 4); gus_rampon(0x40 | 0x20); /* Down, once, with IRQ */ @@ -698,10 +675,9 @@ restore_flags(flags); } -static void -gus_reset(void) +static void gus_reset(void) { - int i; + int i; gus_select_max_voices(24); volume_base = 3071; @@ -709,23 +685,24 @@ volume_method = VOL_METHOD_ADAGIO; for (i = 0; i < 32; i++) - { - gus_voice_init(i); /* Turn voice off */ - gus_voice_init2(i); - } + { + gus_voice_init(i); /* Turn voice off */ + gus_voice_init2(i); + } } -static void -gus_initialize(void) +static void gus_initialize(void) { - unsigned long flags; - unsigned char dma_image, irq_image, tmp; - - static unsigned char gus_irq_map[16] = - {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7}; + unsigned long flags; + unsigned char dma_image, irq_image, tmp; - static unsigned char gus_dma_map[8] = - {0, 1, 0, 2, 0, 3, 4, 5}; + static unsigned char gus_irq_map[16] = { + 0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7 + }; + + static unsigned char gus_dma_map[8] = { + 0, 1, 0, 2, 0, 3, 4, 5 + }; save_flags(flags); cli(); @@ -787,37 +764,39 @@ irq_image = 0; tmp = gus_irq_map[gus_irq]; if (!gus_pnp_flag && !tmp) - printk("Warning! GUS IRQ not selected\n"); + printk(KERN_WARNING "Warning! GUS IRQ not selected\n"); irq_image |= tmp; irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */ dual_dma_mode = 1; if (gus_dma2 == gus_dma || gus_dma2 == -1) - { - dual_dma_mode = 0; - dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ - - tmp = gus_dma_map[gus_dma]; - if (!tmp) - printk("Warning! GUS DMA not selected\n"); + { + dual_dma_mode = 0; + dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */ + + tmp = gus_dma_map[gus_dma]; + if (!tmp) + printk(KERN_WARNING "Warning! GUS DMA not selected\n"); - dma_image |= tmp; - } else + dma_image |= tmp; + } + else + { /* Setup dual DMA channel mode for GUS MAX */ - { - dma_image = gus_dma_map[gus_dma]; - if (!dma_image) - printk("Warning! GUS DMA not selected\n"); - - tmp = gus_dma_map[gus_dma2] << 3; - if (!tmp) - { - printk("Warning! Invalid GUS MAX DMA\n"); - tmp = 0x40; /* Combine DMA channels */ + + dma_image = gus_dma_map[gus_dma]; + if (!dma_image) + printk(KERN_WARNING "Warning! GUS DMA not selected\n"); + + tmp = gus_dma_map[gus_dma2] << 3; + if (!tmp) + { + printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n"); + tmp = 0x40; /* Combine DMA channels */ dual_dma_mode = 0; - } - dma_image |= tmp; - } + } + dma_image |= tmp; + } /* * For some reason the IRQ and DMA addresses must be written twice @@ -848,8 +827,8 @@ mix_image &= ~0x02; /* Enable line out */ mix_image |= 0x08; /* Enable IRQ */ outb((mix_image), u_Mixer); /* - * Turn mixer channels on - * Note! Mic in is left off. + * Turn mixer channels on + * Note! Mic in is left off. */ gus_select_voice(0); /* This disables writes to IRQ/DMA reg */ @@ -869,17 +848,16 @@ } -static void -pnp_mem_init(void) +static void pnp_mem_init(void) { #include "iwmem.h" #define CHUNK_SIZE (256*1024) #define BANK_SIZE (4*1024*1024) #define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE) - int bank, chunk, addr, total = 0; - int bank_sizes[4]; - int i, j, bits = -1, nbanks = 0; + int bank, chunk, addr, total = 0; + int bank_sizes[4]; + int i, j, bits = -1, nbanks = 0; /* * This routine determines what kind of RAM is installed in each of the four @@ -902,133 +880,137 @@ * Perform the DRAM size detection for each bank individually. */ for (bank = 0; bank < 4; bank++) - { - int size = 0; + { + int size = 0; - addr = bank * BANK_SIZE; + addr = bank * BANK_SIZE; - /* Clean check points of each chunk */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - - /* Write a value to each chunk point and verify the result */ - for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) - { - gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55); - gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA); + /* Clean check points of each chunk */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + + /* Write a value to each chunk point and verify the result */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA); - if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 && + if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 && gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA) - { /* OK. There is RAM. Now check for possible shadows */ - int ok = 1, chunk2; + { + /* OK. There is RAM. Now check for possible shadows */ + int ok = 1, chunk2; - for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) - if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) || - gus_peek(addr + chunk2 * CHUNK_SIZE + 1L)) - ok = 0; /* Addressing wraps */ - - if (ok) - size = (chunk + 1) * CHUNK_SIZE; - } - gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); - gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); - } - - bank_sizes[bank] = size; - if (size) - nbanks = bank + 1; - DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); - } + for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) + if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) || + gus_peek(addr + chunk2 * CHUNK_SIZE + 1L)) + ok = 0; /* Addressing wraps */ + + if (ok) + size = (chunk + 1) * CHUNK_SIZE; + } + gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + bank_sizes[bank] = size; + if (size) + nbanks = bank + 1; + DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); + } if (nbanks == 0) /* No RAM - Give up */ - { - printk("Sound: An Interwave audio chip detected but no DRAM\n"); - printk("Sound: Unable to work with this card.\n"); - gus_write8(0x19, gus_read8(0x19) & ~0x01); - gus_mem_size = 0; - return; - } -/* - * Now we know how much DRAM there is in each bank. The next step is - * to find a DRAM size encoding (0 to 12) which is best for the combination - * we have. - * - * First try if any of the possible alternatives matches exactly the amount - * of memory we have. - */ + { + printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n"); + printk(KERN_ERR "Sound: Unable to work with this card.\n"); + gus_write8(0x19, gus_read8(0x19) & ~0x01); + gus_mem_size = 0; + return; + } + + /* + * Now we know how much DRAM there is in each bank. The next step is + * to find a DRAM size encoding (0 to 12) which is best for the combination + * we have. + * + * First try if any of the possible alternatives matches exactly the amount + * of memory we have. + */ for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; + { + bits = i; - for (j = 0; bits != -1 && j < 4; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - } + for (j = 0; bits != -1 && j < 4; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } + + /* + * If necessary, try to find a combination where other than the last + * bank matches our configuration and the last bank is left oversized. + * In this way we don't leave holes in the middle of memory. + */ -/* - * If necessary, try to find a combination where other than the last - * bank matches our configuration and the last bank is left oversized. - * In this way we don't leave holes in the middle of memory. - */ if (bits == -1) /* No luck yet */ + { for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; + { + bits = i; - for (j = 0; bits != -1 && j < nbanks - 1; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) - bits = -1; /* The last bank is too small */ - } -/* - * The last resort is to search for a combination where the last bank is - * smaller than the actual SIMM. This leaves some memory in the last bank - * unused but doesn't leave holes in the DRAM address space. - */ + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) + bits = -1; /* The last bank is too small */ + } + } + /* + * The last resort is to search for a combination where the last bank is + * smaller than the actual SIMM. This leaves some memory in the last bank + * unused but doesn't leave holes in the DRAM address space. + */ if (bits == -1) /* No luck yet */ - { - for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; - - for (j = 0; bits != -1 && j < nbanks - 1; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - } - - if (bits != -1) - { - printk("Interwave: Can't use all installed RAM.\n"); - printk("Interwave: Try reordering SIMMS.\n"); - } - } + { + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } + if (bits != -1) + { + printk(KERN_INFO "Interwave: Can't use all installed RAM.\n"); + printk(KERN_INFO "Interwave: Try reordering SIMMS.\n"); + } + } if (bits == -1) - { - printk("Interwave: Can't find working DRAM encoding.\n"); - printk("Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); - bits = 0; - } + { + printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n"); + printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); + bits = 0; + } DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits)); for (bank = 0; bank < 4; bank++) - { - DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024)); + { + DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024)); - if (bank_sizes[bank] > mem_decode[bits][bank]) - total += mem_decode[bits][bank]; - else - total += bank_sizes[bank]; - } + if (bank_sizes[bank] > mem_decode[bits][bank]) + total += mem_decode[bits][bank]; + else + total += bank_sizes[bank]; + } DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024)); -/* - * Set the memory addressing mode. - */ + + /* + * Set the memory addressing mode. + */ gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits); /* Leave the chip into enhanced mode. Disable LFO */ @@ -1037,8 +1019,7 @@ gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02); } -int -gus_wave_detect(int baseaddr) +int gus_wave_detect(int baseaddr) { unsigned long i, max_mem = 1024L; unsigned long loc; @@ -1059,15 +1040,18 @@ gus_write8(0x5b, ~val); /* Invert all bits */ if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0)) /* No change */ + { if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ - { - DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); - gus_pnp_flag = 1; - } else - { - DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b))); - gus_pnp_flag = 0; - } + { + DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); + gus_pnp_flag = 1; + } + else + { + DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b))); + gus_pnp_flag = 0; + } + } gus_write8(0x5b, val); /* Restore all bits */ #endif @@ -1084,28 +1068,26 @@ /* Now zero it out so that I can check for mirroring .. */ gus_poke(0L, 0x00); for (i = 1L; i < max_mem; i++) - { - int n, failed; + { + int n, failed; - /* check for mirroring ... */ - if (gus_peek(0L) != 0) - break; - loc = i << 10; - - for (n = loc - 1, failed = 0; n <= loc; n++) - { - gus_poke(loc, 0xaa); - if (gus_peek(loc) != 0xaa) - failed = 1; - - gus_poke(loc, 0x55); - if (gus_peek(loc) != 0x55) - failed = 1; - } + /* check for mirroring ... */ + if (gus_peek(0L) != 0) + break; + loc = i << 10; - if (failed) - break; - } + for (n = loc - 1, failed = 0; n <= loc; n++) + { + gus_poke(loc, 0xaa); + if (gus_peek(loc) != 0xaa) + failed = 1; + gus_poke(loc, 0x55); + if (gus_peek(loc) != 0x55) + failed = 1; + } + if (failed) + break; + } gus_mem_size = i << 10; return 1; } @@ -1113,30 +1095,32 @@ static int guswave_ioctl(int dev, unsigned int cmd, caddr_t arg) { - switch (cmd) { - case SNDCTL_SYNTH_INFO: - gus_info.nr_voices = nr_voices; - return __copy_to_user(arg, &gus_info, sizeof(gus_info)); - - case SNDCTL_SEQ_RESETSAMPLES: - reset_sample_memory(); - return 0; + switch (cmd) + { + case SNDCTL_SYNTH_INFO: + gus_info.nr_voices = nr_voices; + if (copy_to_user(arg, &gus_info, sizeof(gus_info))) + return -EFAULT; + return 0; + + case SNDCTL_SEQ_RESETSAMPLES: + reset_sample_memory(); + return 0; - case SNDCTL_SEQ_PERCMODE: - return 0; + case SNDCTL_SEQ_PERCMODE: + return 0; - case SNDCTL_SYNTH_MEMAVL: - return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; + case SNDCTL_SYNTH_MEMAVL: + return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32; - default: - return -EINVAL; + default: + return -EINVAL; } } -static int -guswave_set_instr(int dev, int voice, int instr_no) +static int guswave_set_instr(int dev, int voice, int instr_no) { - int sample_no; + int sample_no; if (instr_no < 0 || instr_no > MAX_PATCH) instr_no = 0; /* Default to acoustic piano */ @@ -1145,103 +1129,97 @@ return -EINVAL; if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].sample_pending = instr_no; - return 0; - } + { + voices[voice].sample_pending = instr_no; + return 0; + } sample_no = patch_table[instr_no]; patch_map[voice] = -1; if (sample_no == NOT_SAMPLE) - { - printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return -EINVAL; /* Patch not defined */ - } + { +/* printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/ + return -EINVAL; /* Patch not defined */ + } if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ - { - printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice); - return -EINVAL; - } + { +/* printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/ + return -EINVAL; + } sample_map[voice] = sample_no; patch_map[voice] = instr_no; return 0; } -static int -guswave_kill_note(int dev, int voice, int note, int velocity) +static int guswave_kill_note(int dev, int voice, int note, int velocity) { - unsigned long flags; + unsigned long flags; save_flags(flags); cli(); /* voice_alloc->map[voice] = 0xffff; */ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].kill_pending = 1; - restore_flags(flags); - } else - { - restore_flags(flags); - gus_voice_fade(voice); - } + { + voices[voice].kill_pending = 1; + restore_flags(flags); + } + else + { + restore_flags(flags); + gus_voice_fade(voice); + } restore_flags(flags); return 0; } -static void -guswave_aftertouch(int dev, int voice, int pressure) +static void guswave_aftertouch(int dev, int voice, int pressure) { } -static void -guswave_panning(int dev, int voice, int value) +static void guswave_panning(int dev, int voice, int value) { if (voice >= 0 || voice < 32) voices[voice].panning = value; } -static void -guswave_volume_method(int dev, int mode) +static void guswave_volume_method(int dev, int mode) { if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO) volume_method = mode; } -static void -compute_volume(int voice, int volume) +static void compute_volume(int voice, int volume) { if (volume < 128) voices[voice].midi_volume = volume; switch (volume_method) - { - case VOL_METHOD_ADAGIO: - voices[voice].initial_volume = - gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol, - voices[voice].expression_vol, - voices[voice].patch_vol); - break; - - case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ - voices[voice].initial_volume = - gus_linear_vol(volume, voices[voice].main_vol); - break; - - default: - voices[voice].initial_volume = volume_base + - (voices[voice].midi_volume * volume_scale); - } + { + case VOL_METHOD_ADAGIO: + voices[voice].initial_volume = + gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol, + voices[voice].expression_vol, + voices[voice].patch_vol); + break; + + case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */ + voices[voice].initial_volume = gus_linear_vol(volume, voices[voice].main_vol); + break; + + default: + voices[voice].initial_volume = volume_base + + (voices[voice].midi_volume * volume_scale); + } if (voices[voice].initial_volume > 4030) voices[voice].initial_volume = 4030; } -static void -compute_and_set_volume(int voice, int volume, int ramp_time) +static void compute_and_set_volume(int voice, int volume, int ramp_time) { - int curr, target, rate; - unsigned long flags; + int curr, target, rate; + unsigned long flags; compute_volume(voice, volume); voices[voice].current_volume = voices[voice].initial_volume; @@ -1249,7 +1227,7 @@ save_flags(flags); cli(); /* - * CAUTION! Interrupts disabled. Enable them before returning + * CAUTION! Interrupts disabled. Enable them before returning */ gus_select_voice(voice); @@ -1258,12 +1236,12 @@ target = voices[voice].initial_volume; if (ramp_time == INSTANT_RAMP) - { - gus_rampoff(); - gus_voice_volume(target); - restore_flags(flags); - return; - } + { + gus_rampoff(); + gus_voice_volume(target); + restore_flags(flags); + return; + } if (ramp_time == FAST_RAMP) rate = 63; else @@ -1271,34 +1249,34 @@ gus_ramp_rate(0, rate); if ((target - curr) / 64 == 0) /* Close enough to target. */ - { - gus_rampoff(); - gus_voice_volume(target); - restore_flags(flags); - return; - } + { + gus_rampoff(); + gus_voice_volume(target); + restore_flags(flags); + return; + } if (target > curr) - { - if (target > (4095 - 65)) - target = 4095 - 65; - gus_ramp_range(curr, target); - gus_rampon(0x00); /* Ramp up, once, no IRQ */ - } else - { - if (target < 65) - target = 65; + { + if (target > (4095 - 65)) + target = 4095 - 65; + gus_ramp_range(curr, target); + gus_rampon(0x00); /* Ramp up, once, no IRQ */ + } + else + { + if (target < 65) + target = 65; - gus_ramp_range(target, curr); - gus_rampon(0x40); /* Ramp down, once, no irq */ - } + gus_ramp_range(target, curr); + gus_rampon(0x40); /* Ramp down, once, no irq */ + } restore_flags(flags); } -static void -dynamic_volume_change(int voice) +static void dynamic_volume_change(int voice) { - unsigned char status; - unsigned long flags; + unsigned char status; + unsigned long flags; save_flags(flags); cli(); @@ -1310,10 +1288,11 @@ return; /* Voice was not running */ if (!(voices[voice].mode & WAVE_ENVELOPES)) - { - compute_and_set_volume(voice, voices[voice].midi_volume, 1); - return; - } + { + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } + /* * Voice is running and has envelopes. */ @@ -1325,10 +1304,10 @@ restore_flags(flags); if (status & 0x03) /* Sustain phase? */ - { - compute_and_set_volume(voice, voices[voice].midi_volume, 1); - return; - } + { + compute_and_set_volume(voice, voices[voice].midi_volume, 1); + return; + } if (voices[voice].env_phase < 0) return; @@ -1336,8 +1315,7 @@ } -static void -guswave_controller(int dev, int voice, int ctrl_num, int value) +static void guswave_controller(int dev, int voice, int ctrl_num, int value) { unsigned long flags; unsigned long freq; @@ -1346,88 +1324,84 @@ return; switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - voices[voice].bender = value; - - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - { - freq = compute_finetune(voices[voice].orig_freq, value, - voices[voice].bender_range, 0); - voices[voice].current_freq = freq; - - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_freq(freq); - restore_flags(flags); - } - break; - - case CTRL_PITCH_BENDER_RANGE: - voices[voice].bender_range = value; - break; - case CTL_EXPRESSION: - value /= 128; - case CTRL_EXPRESSION: - if (volume_method == VOL_METHOD_ADAGIO) - { - voices[voice].expression_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change(voice); - } - break; - - case CTL_PAN: - voices[voice].panning = (value * 2) - 128; - break; - - case CTL_MAIN_VOLUME: - value = (value * 100) / 16383; - - case CTRL_MAIN_VOLUME: - voices[voice].main_vol = value; - if (voices[voice].volume_irq_mode != VMODE_START_NOTE) - dynamic_volume_change(voice); - break; + { + case CTRL_PITCH_BENDER: + voices[voice].bender = value; - default: - break; - } + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + { + freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0); + voices[voice].current_freq = freq; + + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(freq); + restore_flags(flags); + } + break; + + case CTRL_PITCH_BENDER_RANGE: + voices[voice].bender_range = value; + break; + case CTL_EXPRESSION: + value /= 128; + case CTRL_EXPRESSION: + if (volume_method == VOL_METHOD_ADAGIO) + { + voices[voice].expression_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + } + break; + + case CTL_PAN: + voices[voice].panning = (value * 2) - 128; + break; + + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; + + case CTRL_MAIN_VOLUME: + voices[voice].main_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change(voice); + break; + + default: + break; + } } -static int -guswave_start_note2(int dev, int voice, int note_num, int volume) +static int guswave_start_note2(int dev, int voice, int note_num, int volume) { - int sample, best_sample, best_delta, delta_freq; - int is16bits, samplep, patch, pan; + int sample, best_sample, best_delta, delta_freq; + int is16bits, samplep, patch, pan; unsigned long note_freq, base_note, freq, flags; unsigned char mode = 0; if (voice < 0 || voice > 31) - { - printk("GUS: Invalid voice\n"); - return -EINVAL; - } + { +/* printk("GUS: Invalid voice\n");*/ + return -EINVAL; + } if (note_num == 255) - { - if (voices[voice].mode & WAVE_ENVELOPES) - { - voices[voice].midi_volume = volume; - dynamic_volume_change(voice); - return 0; - } - compute_and_set_volume(voice, volume, 1); - return 0; - } + { + if (voices[voice].mode & WAVE_ENVELOPES) + { + voices[voice].midi_volume = volume; + dynamic_volume_change(voice); + return 0; + } + compute_and_set_volume(voice, volume, 1); + return 0; + } if ((patch = patch_map[voice]) == -1) - { - return -EINVAL; - } + return -EINVAL; if ((samplep = patch_table[patch]) == NOT_SAMPLE) - { - return -EINVAL; - } + { + return -EINVAL; + } note_freq = note_to_freq(note_num); /* @@ -1439,29 +1413,31 @@ best_sample = samplep; best_delta = 1000000; while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1) - { - delta_freq = note_freq - samples[samplep].base_note; - if (delta_freq < 0) - delta_freq = -delta_freq; - if (delta_freq < best_delta) - { - best_sample = samplep; - best_delta = delta_freq; - } - if (samples[samplep].low_note <= note_freq && - note_freq <= samples[samplep].high_note) - sample = samplep; - else - samplep = samples[samplep].key; /* Link to next sample */ + { + delta_freq = note_freq - samples[samplep].base_note; + if (delta_freq < 0) + delta_freq = -delta_freq; + if (delta_freq < best_delta) + { + best_sample = samplep; + best_delta = delta_freq; + } + if (samples[samplep].low_note <= note_freq && + note_freq <= samples[samplep].high_note) + { + sample = samplep; + } + else + samplep = samples[samplep].key; /* Link to next sample */ } if (sample == -1) sample = best_sample; if (sample == -1) - { - printk("GUS: Patch %d not defined for note %d\n", patch, note_num); - return 0; /* Should play default patch ??? */ - } + { +/* printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/ + return 0; /* Should play default patch ??? */ + } is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; voices[voice].mode = samples[sample].mode; voices[voice].patch_vol = samples[sample].volume; @@ -1470,27 +1446,28 @@ gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */ if (voices[voice].mode & WAVE_ENVELOPES) - { - int i; + { + int i; - for (i = 0; i < 6; i++) - { - voices[voice].env_rate[i] = samples[sample].env_rate[i]; - voices[voice].env_offset[i] = samples[sample].env_offset[i]; - } - } + for (i = 0; i < 6; i++) + { + voices[voice].env_rate[i] = samples[sample].env_rate[i]; + voices[voice].env_offset[i] = samples[sample].env_offset[i]; + } + } sample_map[voice] = sample; if (voices[voice].fixed_pitch) /* Fixed pitch */ - { + { freq = samples[sample].base_freq; - } else - { - base_note = samples[sample].base_note / 100; - note_freq /= 100; + } + else + { + base_note = samples[sample].base_note / 100; + note_freq /= 100; - freq = samples[sample].base_freq * note_freq / base_note; - } + freq = samples[sample].base_freq * note_freq / base_note; + } voices[voice].orig_freq = freq; @@ -1511,15 +1488,15 @@ pan = 15; if (samples[sample].mode & WAVE_16_BITS) - { - mode |= 0x04; /* 16 bits */ - if ((sample_ptrs[sample] / GUS_BANK_SIZE) != - ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) - printk("GUS: Sample address error\n"); - } - /************************************************************************* - * CAUTION! Interrupts disabled. Don't return before enabling - *************************************************************************/ + { + mode |= 0x04; /* 16 bits */ + if ((sample_ptrs[sample] / GUS_BANK_SIZE) != + ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE)) + printk(KERN_ERR "GUS: Sample address error\n"); + } + /************************************************************************* + * CAUTION! Interrupts disabled. Don't return before enabling + *************************************************************************/ save_flags(flags); cli(); @@ -1530,13 +1507,14 @@ restore_flags(flags); if (voices[voice].mode & WAVE_ENVELOPES) - { - compute_volume(voice, volume); - init_envelope(voice); - } else - { - compute_and_set_volume(voice, volume, 0); - } + { + compute_volume(voice, volume); + init_envelope(voice); + } + else + { + compute_and_set_volume(voice, volume, 0); + } save_flags(flags); cli(); @@ -1544,43 +1522,38 @@ if (samples[sample].mode & WAVE_LOOP_BACK) gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len - - voices[voice].offset_pending, 0, is16bits); /* start=end */ + voices[voice].offset_pending, 0, is16bits); /* start=end */ else - gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, - 0, is16bits); /* Sample start=begin */ + gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits); /* Sample start=begin */ if (samples[sample].mode & WAVE_LOOPING) - { - mode |= 0x08; + { + mode |= 0x08; - if (samples[sample].mode & WAVE_BIDIR_LOOP) - mode |= 0x10; + if (samples[sample].mode & WAVE_BIDIR_LOOP) + mode |= 0x10; - if (samples[sample].mode & WAVE_LOOP_BACK) - { - gus_write_addr(0x0a, - sample_ptrs[sample] + samples[sample].loop_end - + if (samples[sample].mode & WAVE_LOOP_BACK) + { + gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end - voices[voice].offset_pending, (samples[sample].fractions >> 4) & 0x0f, is16bits); - mode |= 0x40; - } - gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start, - samples[sample].fractions & 0x0f, - is16bits); /* Loop start location */ - gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end, - (samples[sample].fractions >> 4) & 0x0f, - is16bits); /* Loop end location */ - } else - { - mode |= 0x20; /* Loop IRQ at the end */ - voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ - voices[voice].loop_irq_parm = 1; - gus_write_addr(0x02, sample_ptrs[sample], - 0, is16bits); /* Loop start location */ - gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1, - (samples[sample].fractions >> 4) & 0x0f, - is16bits); /* Loop end location */ - } + mode |= 0x40; + } + gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start, + samples[sample].fractions & 0x0f, is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end, + (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ + } + else + { + mode |= 0x20; /* Loop IRQ at the end */ + voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ + voices[voice].loop_irq_parm = 1; + gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits); /* Loop start location */ + gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1, + (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ + } gus_voice_freq(freq); gus_voice_balance(pan); gus_voice_on(mode); @@ -1595,82 +1568,81 @@ * ramping. */ -static int -guswave_start_note(int dev, int voice, int note_num, int volume) +static int guswave_start_note(int dev, int voice, int note_num, int volume) { - long int flags; - int mode; - int ret_val = 0; + long int flags; + int mode; + int ret_val = 0; save_flags(flags); cli(); if (note_num == 255) - { - if (voices[voice].volume_irq_mode == VMODE_START_NOTE) - { - voices[voice].volume_pending = volume; - } else - { - ret_val = guswave_start_note2(dev, voice, note_num, volume); - } - } else - { - gus_select_voice(voice); - mode = gus_read8(0x00); - if (mode & 0x20) - gus_write8(0x00, mode & 0xdf); /* No interrupt! */ - - voices[voice].offset_pending = 0; - voices[voice].kill_pending = 0; - voices[voice].volume_irq_mode = 0; - voices[voice].loop_irq_mode = 0; - - if (voices[voice].sample_pending >= 0) - { - restore_flags(flags); /* Run temporarily with interrupts enabled */ - guswave_set_instr(voices[voice].dev_pending, voice, - voices[voice].sample_pending); - voices[voice].sample_pending = -1; - save_flags(flags); - cli(); - gus_select_voice(voice); /* Reselect the voice (just to be sure) */ - } - if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065)) - { - ret_val = guswave_start_note2(dev, voice, note_num, volume); - } else - { - voices[voice].dev_pending = dev; - voices[voice].note_pending = note_num; - voices[voice].volume_pending = volume; - voices[voice].volume_irq_mode = VMODE_START_NOTE; - - gus_rampoff(); - gus_ramp_range(2000, 4065); - gus_ramp_rate(0, 63); /* Fastest possible rate */ - gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */ - } - } + { + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].volume_pending = volume; + } + else + { + ret_val = guswave_start_note2(dev, voice, note_num, volume); + } + } + else + { + gus_select_voice(voice); + mode = gus_read8(0x00); + if (mode & 0x20) + gus_write8(0x00, mode & 0xdf); /* No interrupt! */ + + voices[voice].offset_pending = 0; + voices[voice].kill_pending = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].loop_irq_mode = 0; + + if (voices[voice].sample_pending >= 0) + { + restore_flags(flags); /* Run temporarily with interrupts enabled */ + guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending); + voices[voice].sample_pending = -1; + save_flags(flags); + cli(); + gus_select_voice(voice); /* Reselect the voice (just to be sure) */ + } + if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065)) + { + ret_val = guswave_start_note2(dev, voice, note_num, volume); + } + else + { + voices[voice].dev_pending = dev; + voices[voice].note_pending = note_num; + voices[voice].volume_pending = volume; + voices[voice].volume_irq_mode = VMODE_START_NOTE; + + gus_rampoff(); + gus_ramp_range(2000, 4065); + gus_ramp_rate(0, 63); /* Fastest possible rate */ + gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */ + } + } restore_flags(flags); return ret_val; } -static void -guswave_reset(int dev) +static void guswave_reset(int dev) { - int i; + int i; for (i = 0; i < 32; i++) - { - gus_voice_init(i); - gus_voice_init2(i); - } + { + gus_voice_init(i); + gus_voice_init2(i); + } } -static int -guswave_open(int dev, int mode) +static int guswave_open(int dev, int mode) { - int err; + int err; if (gus_busy) return -EBUSY; @@ -1678,13 +1650,14 @@ voice_alloc->timestamp = 0; if ((err = DMAbuf_open_dma(gus_devnum)) < 0) - { - /* printk( "GUS: Loading samples without DMA\n"); */ - gus_no_dma = 1; /* Upload samples using PIO */ - } else + { + /* printk( "GUS: Loading samples without DMA\n"); */ + gus_no_dma = 1; /* Upload samples using PIO */ + } + else gus_no_dma = 0; - dram_sleep_flag.opts = WK_NONE; + init_waitqueue(&dram_sleeper); gus_busy = 1; active_device = GUS_DEV_WAVE; @@ -1696,8 +1669,7 @@ return 0; } -static void -guswave_close(int dev) +static void guswave_close(int dev) { gus_busy = 0; active_device = 0; @@ -1707,35 +1679,34 @@ DMAbuf_close_dma(gus_devnum); } -static int -guswave_load_patch(int dev, int format, const char *addr, +static int guswave_load_patch(int dev, int format, const char *addr, int offs, int count, int pmgr_flag) { struct patch_info patch; - int instr; - long sizeof_patch; + int instr; + long sizeof_patch; - unsigned long blk_sz, blk_end, left, src_offs, target; + unsigned long blk_sz, blk_end, left, src_offs, target; sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */ if (format != GUS_PATCH) - { - printk("GUS Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; - } + { +/* printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/ + return -EINVAL; + } if (count < sizeof_patch) - { - printk("GUS Error: Patch header too short\n"); + { +/* printk("GUS Error: Patch header too short\n");*/ return -EINVAL; - } + } count -= sizeof_patch; if (free_sample >= MAX_SAMPLE) - { - printk("GUS: Sample table full\n"); + { +/* printk("GUS: Sample table full\n");*/ return -ENOSPC; - } + } /* * Copy the header from user space but ignore the first bytes which have * been transferred already. @@ -1746,63 +1717,63 @@ if (patch.mode & WAVE_ROM) return -EINVAL; if (gus_mem_size == 0) - return -ENOSPC; instr = patch.instr_no; if (instr < 0 || instr > MAX_PATCH) - { - printk("GUS: Invalid patch number %d\n", instr); - return -EINVAL; - } + { +/* printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/ + return -EINVAL; + } if (count < patch.len) - { - printk("GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len); - patch.len = count; - } + { +/* printk(KERN_ERR "GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len);*/ + patch.len = count; + } if (patch.len <= 0 || patch.len > gus_mem_size) - { - printk("GUS: Invalid sample length %d\n", (int) patch.len); - return -EINVAL; - } + { +/* printk(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/ + return -EINVAL; + } if (patch.mode & WAVE_LOOPING) - { - if (patch.loop_start < 0 || patch.loop_start >= patch.len) - { - printk("GUS: Invalid loop start\n"); - return -EINVAL; - } - if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) - { - printk("GUS: Invalid loop end\n"); - return -EINVAL; - } - } + { + if (patch.loop_start < 0 || patch.loop_start >= patch.len) + { +/* printk(KERN_ERR "GUS: Invalid loop start\n");*/ + return -EINVAL; + } + if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) + { +/* printk(KERN_ERR "GUS: Invalid loop end\n");*/ + return -EINVAL; + } + } free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */ if (patch.mode & WAVE_16_BITS) - { - /* - * 16 bit samples must fit one 256k bank. - */ - if (patch.len >= GUS_BANK_SIZE) - { - printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len); - return -ENOSPC; - } - if ((free_mem_ptr / GUS_BANK_SIZE) != - ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) - { - unsigned long tmp_mem = /* Align to 256K */ - ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; + { + /* + * 16 bit samples must fit one 256k bank. + */ + if (patch.len >= GUS_BANK_SIZE) + { +/* printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len);*/ + return -ENOSPC; + } + if ((free_mem_ptr / GUS_BANK_SIZE) != + ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) + { + unsigned long tmp_mem = + /* Align to 256K */ + ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; - if ((tmp_mem + patch.len) > gus_mem_size) - return -ENOSPC; + if ((tmp_mem + patch.len) > gus_mem_size) + return -ENOSPC; - free_mem_ptr = tmp_mem; /* This leaves unusable memory */ - } - } + free_mem_ptr = tmp_mem; /* This leaves unusable memory */ + } + } if ((free_mem_ptr + patch.len) > gus_mem_size) return -ENOSPC; @@ -1816,9 +1787,9 @@ patch.mode &= ~WAVE_TREMOLO; if (!(patch.mode & WAVE_FRACTIONS)) - { + { patch.fractions = 0; - } + } memcpy((char *) &samples[free_sample], &patch, sizeof_patch); /* @@ -1837,162 +1808,147 @@ target = free_mem_ptr; while (left) /* Not completely transferred yet */ - { - blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; - if (blk_sz > left) - blk_sz = left; - - /* - * DMA cannot cross bank (256k) boundaries. Check for that. - */ - blk_end = target + blk_sz; - - if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) - { /* Split the block */ - - blk_end &= ~(GUS_BANK_SIZE - 1); - blk_sz = blk_end - target; - } - if (gus_no_dma) - { - /* - * For some reason the DMA is not possible. We have to use PIO. - */ - long i; - unsigned char data; - - for (i = 0; i < blk_sz; i++) - { - get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i])); - if (patch.mode & WAVE_UNSIGNED) - if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) - data ^= 0x80; /* Convert to signed */ - gus_poke(target + i, data); - } - } else - { - unsigned long address, hold_address; - unsigned char dma_command; - unsigned long flags; - - if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) - { - printk("GUS: DMA buffer == NULL\n"); - return -ENOSPC; - } - /* - * OK, move now. First in and then out. - */ - - copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); - - save_flags(flags); - cli(); -/******** INTERRUPTS DISABLED NOW ********/ - gus_write8(0x41, 0); /* Disable GF1 DMA */ - DMAbuf_start_dma(gus_devnum, - audio_devs[gus_devnum]->dmap_out->raw_buf_phys, - blk_sz, DMA_MODE_WRITE); - - /* - * Set the DRAM address for the wave data - */ - - if (iw_mode) - { - /* Different address translation in enhanced mode */ - - unsigned char hi; - - if (gus_dma > 4) - address = target >> 1; /* Convert to 16 bit word address */ - else - address = target; - - hi = (unsigned char) ((address >> 16) & 0xf0); - hi += (unsigned char) (address & 0x0f); - - gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */ - gus_write8(0x50, hi); - } else - { - address = target; + { + blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; + if (blk_sz > left) + blk_sz = left; - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } - gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ - } + /* + * DMA cannot cross bank (256k) boundaries. Check for that. + */ + + blk_end = target + blk_sz; - /* - * Start the DMA transfer - */ - - dma_command = 0x21; /* IRQ enable, DMA start */ - if (patch.mode & WAVE_UNSIGNED) - dma_command |= 0x80; /* Invert MSB */ - if (patch.mode & WAVE_16_BITS) - dma_command |= 0x40; /* 16 bit _DATA_ */ - if (audio_devs[gus_devnum]->dmap_out->dma > 3) - dma_command |= 0x04; /* 16 bit DMA _channel_ */ - - gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */ - - /* - * Sleep here until the DRAM DMA done interrupt is served - */ - active_device = GUS_DEV_WAVE; - - - { - unsigned long tlimit; - - if (HZ) - current->timeout = tlimit = jiffies + (HZ); - else - tlimit = (unsigned long) -1; - dram_sleep_flag.opts = WK_SLEEP; - interruptible_sleep_on(&dram_sleeper); - if (!(dram_sleep_flag.opts & WK_WAKEUP)) - { - if (jiffies >= tlimit) - dram_sleep_flag.opts |= WK_TIMEOUT; - } - dram_sleep_flag.opts &= ~WK_SLEEP; - }; - if ((dram_sleep_flag.opts & WK_TIMEOUT)) - printk("GUS: DMA Transfer timed out\n"); - restore_flags(flags); - } - - /* - * Now the next part - */ - - left -= blk_sz; - src_offs += blk_sz; - target += blk_sz; + if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE)) + { + /* Split the block */ + blk_end &= ~(GUS_BANK_SIZE - 1); + blk_sz = blk_end - target; + } + if (gus_no_dma) + { + /* + * For some reason the DMA is not possible. We have to use PIO. + */ + long i; + unsigned char data; - gus_write8(0x41, 0); /* Stop DMA */ - } + for (i = 0; i < blk_sz; i++) + { + get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[sizeof_patch + i])); + if (patch.mode & WAVE_UNSIGNED) + if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) + data ^= 0x80; /* Convert to signed */ + gus_poke(target + i, data); + } + } + else + { + unsigned long address, hold_address; + unsigned char dma_command; + unsigned long flags; - free_mem_ptr += patch.len; + if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) + { + printk(KERN_ERR "GUS: DMA buffer == NULL\n"); + return -ENOSPC; + } + /* + * OK, move now. First in and then out. + */ + + copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); + + save_flags(flags); + cli(); + /******** INTERRUPTS DISABLED NOW ********/ + gus_write8(0x41, 0); /* Disable GF1 DMA */ + DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys, + blk_sz, DMA_MODE_WRITE); + + /* + * Set the DRAM address for the wave data + */ + + if (iw_mode) + { + /* Different address translation in enhanced mode */ + + unsigned char hi; + + if (gus_dma > 4) + address = target >> 1; /* Convert to 16 bit word address */ + else + address = target; + + hi = (unsigned char) ((address >> 16) & 0xf0); + hi += (unsigned char) (address & 0x0f); + + gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */ + gus_write8(0x50, hi); + } + else + { + address = target; + if (audio_devs[gus_devnum]->dmap_out->dma > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ + } + + /* + * Start the DMA transfer + */ + + dma_command = 0x21; /* IRQ enable, DMA start */ + if (patch.mode & WAVE_UNSIGNED) + dma_command |= 0x80; /* Invert MSB */ + if (patch.mode & WAVE_16_BITS) + dma_command |= 0x40; /* 16 bit _DATA_ */ + if (audio_devs[gus_devnum]->dmap_out->dma > 3) + dma_command |= 0x04; /* 16 bit DMA _channel_ */ + + gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */ + + /* + * Sleep here until the DRAM DMA done interrupt is served + */ + active_device = GUS_DEV_WAVE; + + current->timeout = jiffies + HZ; + interruptible_sleep_on(&dram_sleeper); + if (!current->timeout) + printk("GUS: DMA Transfer timed out\n"); + current->timeout = 0; + restore_flags(flags); + } + + /* + * Now the next part + */ + + left -= blk_sz; + src_offs += blk_sz; + target += blk_sz; + + gus_write8(0x41, 0); /* Stop DMA */ + } + free_mem_ptr += patch.len; free_sample++; return 0; } -static void -guswave_hw_control(int dev, unsigned char *event_rec) +static void guswave_hw_control(int dev, unsigned char *event_rec) { - int voice, cmd; - unsigned short p1, p2; - unsigned int plong; - unsigned flags; + int voice, cmd; + unsigned short p1, p2; + unsigned int plong; + unsigned flags; cmd = event_rec[2]; voice = event_rec[3]; @@ -2001,156 +1957,152 @@ plong = *(unsigned int *) &event_rec[4]; if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && - (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) + (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) do_volume_irq(voice); switch (cmd) - { + { + case _GUS_NUMVOICES: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_select_max_voices(p1); + restore_flags(flags); + break; - case _GUS_NUMVOICES: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_select_max_voices(p1); - restore_flags(flags); - break; - - case _GUS_VOICESAMPLE: - guswave_set_instr(dev, voice, p1); - break; - - case _GUS_VOICEON: - save_flags(flags); - cli(); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_on(p1); - restore_flags(flags); - break; - - case _GUS_VOICEOFF: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_off(); - restore_flags(flags); - break; - - case _GUS_VOICEFADE: - gus_voice_fade(voice); - break; - - case _GUS_VOICEMODE: - save_flags(flags); - cli(); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_voice_mode(p1); - restore_flags(flags); - break; - - case _GUS_VOICEBALA: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_balance(p1); - restore_flags(flags); - break; - - case _GUS_VOICEFREQ: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_freq(plong); - restore_flags(flags); - break; - - case _GUS_VOICEVOL: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_voice_volume(p1); - restore_flags(flags); - break; - - case _GUS_VOICEVOL2: /* Just update the software voice level */ - voices[voice].initial_volume = - voices[voice].current_volume = p1; - break; - - case _GUS_RAMPRANGE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_ramp_range(p1, p2); - restore_flags(flags); - break; - - case _GUS_RAMPRATE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NJET-NJET */ - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_ramp_rate(p1, p2); - restore_flags(flags); - break; - - case _GUS_RAMPMODE: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NO-NO */ - save_flags(flags); - cli(); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_ramp_mode(p1); - restore_flags(flags); - break; - - case _GUS_RAMPON: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* EI-EI */ - save_flags(flags); - cli(); - gus_select_voice(voice); - p1 &= ~0x20; /* Don't allow interrupts */ - gus_rampon(p1); - restore_flags(flags); - break; - - case _GUS_RAMPOFF: - if (voices[voice].mode & WAVE_ENVELOPES) - break; /* NEJ-NEJ */ - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_rampoff(); - restore_flags(flags); - break; - - case _GUS_VOLUME_SCALE: - volume_base = p1; - volume_scale = p2; - break; - - case _GUS_VOICE_POS: - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_set_voice_pos(voice, plong); - restore_flags(flags); - break; + case _GUS_VOICESAMPLE: + guswave_set_instr(dev, voice, p1); + break; - default:; - } + case _GUS_VOICEON: + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_on(p1); + restore_flags(flags); + break; + + case _GUS_VOICEOFF: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_off(); + restore_flags(flags); + break; + + case _GUS_VOICEFADE: + gus_voice_fade(voice); + break; + + case _GUS_VOICEMODE: + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_voice_mode(p1); + restore_flags(flags); + break; + + case _GUS_VOICEBALA: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_balance(p1); + restore_flags(flags); + break; + + case _GUS_VOICEFREQ: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_freq(plong); + restore_flags(flags); + break; + + case _GUS_VOICEVOL: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_voice_volume(p1); + restore_flags(flags); + break; + + case _GUS_VOICEVOL2: /* Just update the software voice level */ + voices[voice].initial_volume = voices[voice].current_volume = p1; + break; + + case _GUS_RAMPRANGE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_ramp_range(p1, p2); + restore_flags(flags); + break; + + case _GUS_RAMPRATE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NJET-NJET */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_ramp_rate(p1, p2); + restore_flags(flags); + break; + + case _GUS_RAMPMODE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NO-NO */ + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_ramp_mode(p1); + restore_flags(flags); + break; + + case _GUS_RAMPON: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* EI-EI */ + save_flags(flags); + cli(); + gus_select_voice(voice); + p1 &= ~0x20; /* Don't allow interrupts */ + gus_rampon(p1); + restore_flags(flags); + break; + + case _GUS_RAMPOFF: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* NEJ-NEJ */ + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + restore_flags(flags); + break; + + case _GUS_VOLUME_SCALE: + volume_base = p1; + volume_scale = p2; + break; + + case _GUS_VOICE_POS: + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_set_voice_pos(voice, plong); + restore_flags(flags); + break; + + default: + } } -static int -gus_audio_set_speed(int speed) +static int gus_audio_set_speed(int speed) { - if (speed <= 0) speed = gus_audio_speed; @@ -2163,18 +2115,17 @@ gus_audio_speed = speed; if (only_read_access) - { - /* Compute nearest valid recording speed and return it */ + { + /* Compute nearest valid recording speed and return it */ - /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ - speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; - speed = (9878400 / (speed * 16)) - 2; - } + /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ + speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; + speed = (9878400 / (speed * 16)) - 2; + } return speed; } -static int -gus_audio_set_channels(int channels) +static int gus_audio_set_channels(int channels) { if (!channels) return gus_audio_channels; @@ -2186,8 +2137,7 @@ return channels; } -static int -gus_audio_set_bits(int bits) +static int gus_audio_set_bits(int bits) { if (!bits) return gus_audio_bits; @@ -2206,70 +2156,75 @@ { int val; - switch (cmd) { - case SOUND_PCM_WRITE_RATE: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = gus_audio_set_speed(val); - return __put_user(val, (int *)arg); + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = gus_audio_set_speed(val); + break; - case SOUND_PCM_READ_RATE: - return __put_user(gus_audio_speed, (int *)arg); + case SOUND_PCM_READ_RATE: + val = gus_audio_speed; + break; - case SNDCTL_DSP_STEREO: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = gus_audio_set_channels(val + 1) - 1; - return __put_user(val, (int *)arg); + case SNDCTL_DSP_STEREO: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = gus_audio_set_channels(val + 1) - 1; + break; - case SOUND_PCM_WRITE_CHANNELS: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = gus_audio_set_channels(val); - return __put_user(val, (int *)arg); + case SOUND_PCM_WRITE_CHANNELS: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = gus_audio_set_channels(val); + break; - case SOUND_PCM_READ_CHANNELS: - return __put_user(gus_audio_channels, (int *)arg); + case SOUND_PCM_READ_CHANNELS: + val = gus_audio_channels; + break; - case SNDCTL_DSP_SETFMT: - if (__get_user(val, (int *)arg)) - return -EFAULT; - val = gus_audio_set_bits(val); - return __put_user(val, (int *)arg); + case SNDCTL_DSP_SETFMT: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = gus_audio_set_bits(val); + break; - case SOUND_PCM_READ_BITS: - return __put_user(gus_audio_bits, (int *)arg); + case SOUND_PCM_READ_BITS: + val = gus_audio_bits; + break; - case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ - case SOUND_PCM_READ_FILTER: - return __put_user(-EINVAL, (int *)arg); + case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ + case SOUND_PCM_READ_FILTER: + val = -EINVAL; + break; + default: + return -EINVAL; } - return -EINVAL; + return put_user(val, (int *)arg); } -static void -gus_audio_reset(int dev) +static void gus_audio_reset(int dev) { if (recording_active) - { - gus_write8(0x49, 0x00); /* Halt recording */ - set_input_volumes(); - } + { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } } -static int saved_iw_mode; /* A hack hack hack */ +static int saved_iw_mode; /* A hack hack hack */ -static int -gus_audio_open(int dev, int mode) +static int gus_audio_open(int dev, int mode) { if (gus_busy) return -EBUSY; if (gus_pnp_flag && mode & OPEN_READ) - { - printk("GUS: Audio device #%d is playback only.\n", dev); - return -EIO; - } + { +/* printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/ + return -EIO; + } gus_initialize(); gus_busy = 1; @@ -2280,19 +2235,19 @@ gus_select_max_voices(14); saved_iw_mode = iw_mode; if (iw_mode) - { - /* There are some problems with audio in enhanced mode so disable it */ - gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */ - iw_mode = 0; - } + { + /* There are some problems with audio in enhanced mode so disable it */ + gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */ + iw_mode = 0; + } pcm_active = 0; dma_active = 0; pcm_opened = 1; if (mode & OPEN_READ) - { - recording_active = 1; - set_input_volumes(); - } + { + recording_active = 1; + set_input_volumes(); + } only_read_access = !(mode & OPEN_WRITE); only_8_bits = mode & OPEN_READ; if (only_8_bits) @@ -2303,8 +2258,7 @@ return 0; } -static void -gus_audio_close(int dev) +static void gus_audio_close(int dev) { iw_mode = saved_iw_mode; gus_reset(); @@ -2313,40 +2267,38 @@ active_device = 0; if (recording_active) - { - gus_write8(0x49, 0x00); /* Halt recording */ - set_input_volumes(); - } + { + gus_write8(0x49, 0x00); /* Halt recording */ + set_input_volumes(); + } recording_active = 0; } -static void -gus_audio_update_volume(void) +static void gus_audio_update_volume(void) { - unsigned long flags; - int voice; + unsigned long flags; + int voice; if (pcm_active && pcm_opened) for (voice = 0; voice < gus_audio_channels; voice++) - { - save_flags(flags); - cli(); - gus_select_voice(voice); - gus_rampoff(); - gus_voice_volume(1530 + (25 * gus_pcm_volume)); - gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); - restore_flags(flags); - } + { + save_flags(flags); + cli(); + gus_select_voice(voice); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + restore_flags(flags); + } } -static void -play_next_pcm_block(void) +static void play_next_pcm_block(void) { - unsigned long flags; - int speed = gus_audio_speed; - int this_one, is16bits, chn; - unsigned long dram_loc; - unsigned char mode[2], ramp_mode[2]; + unsigned long flags; + int speed = gus_audio_speed; + int this_one, is16bits, chn; + unsigned long dram_loc; + unsigned char mode[2], ramp_mode[2]; if (!pcm_qlen) return; @@ -2354,95 +2306,91 @@ this_one = pcm_head; for (chn = 0; chn < gus_audio_channels; chn++) - { - mode[chn] = 0x00; - ramp_mode[chn] = 0x03; /* Ramping and rollover off */ - - if (chn == 0) - { - mode[chn] |= 0x20; /* Loop IRQ */ - voices[chn].loop_irq_mode = LMODE_PCM; - } - if (gus_audio_bits != 8) - { - is16bits = 1; - mode[chn] |= 0x04; /* 16 bit data */ - } else - is16bits = 0; - - dram_loc = this_one * pcm_bsize; - dram_loc += chn * pcm_banksize; - - if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ - { - mode[chn] |= 0x08; /* Enable loop */ - ramp_mode[chn] = 0x03; /* Disable rollover bit */ - } else - { - if (chn == 0) - ramp_mode[chn] = 0x04; /* Enable rollover bit */ - } - - save_flags(flags); - cli(); - gus_select_voice(chn); - gus_voice_freq(speed); - - if (gus_audio_channels == 1) - gus_voice_balance(7); /* mono */ - else if (chn == 0) - gus_voice_balance(0); /* left */ - else - gus_voice_balance(15); /* right */ - - if (!pcm_active) /* Playback not already active */ - { - /* - * The playback was not started yet (or there has been a pause). - * Start the voice (again) and ask for a rollover irq at the end of - * this_one block. If this_one one is last of the buffers, use just - * the normal loop with irq. - */ - - gus_voice_off(); - gus_rampoff(); - gus_voice_volume(1530 + (25 * gus_pcm_volume)); - gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); + { + mode[chn] = 0x00; + ramp_mode[chn] = 0x03; /* Ramping and rollover off */ - gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ - gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ + if (chn == 0) + { + mode[chn] |= 0x20; /* Loop IRQ */ + voices[chn].loop_irq_mode = LMODE_PCM; + } + if (gus_audio_bits != 8) + { + is16bits = 1; + mode[chn] |= 0x04; /* 16 bit data */ + } + else + is16bits = 0; - if (chn != 0) - gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, - 0, is16bits); /* Loop end location */ - } - if (chn == 0) - gus_write_addr(0x04, dram_loc + pcm_bsize - 1, - 0, is16bits); /* Loop end location */ - else - mode[chn] |= 0x08; /* Enable looping */ + dram_loc = this_one * pcm_bsize; + dram_loc += chn * pcm_banksize; + if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */ + { + mode[chn] |= 0x08; /* Enable loop */ + ramp_mode[chn] = 0x03; /* Disable rollover bit */ + } + else + { + if (chn == 0) + ramp_mode[chn] = 0x04; /* Enable rollover bit */ + } + save_flags(flags); + cli(); + gus_select_voice(chn); + gus_voice_freq(speed); + + if (gus_audio_channels == 1) + gus_voice_balance(7); /* mono */ + else if (chn == 0) + gus_voice_balance(0); /* left */ + else + gus_voice_balance(15); /* right */ - restore_flags(flags); - } + if (!pcm_active) /* Playback not already active */ + { + /* + * The playback was not started yet (or there has been a pause). + * Start the voice (again) and ask for a rollover irq at the end of + * this_one block. If this_one one is last of the buffers, use just + * the normal loop with irq. + */ + + gus_voice_off(); + gus_rampoff(); + gus_voice_volume(1530 + (25 * gus_pcm_volume)); + gus_ramp_range(65, 1530 + (25 * gus_pcm_volume)); - for (chn = 0; chn < gus_audio_channels; chn++) - { - save_flags(flags); - cli(); - gus_select_voice(chn); - gus_write8(0x0d, ramp_mode[chn]); - if (iw_mode) - gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */ - gus_voice_on(mode[chn]); - restore_flags(flags); - } + gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */ + gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ + if (chn != 0) + gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, + 0, is16bits); /* Loop end location */ + } + if (chn == 0) + gus_write_addr(0x04, dram_loc + pcm_bsize - 1, + 0, is16bits); /* Loop end location */ + else + mode[chn] |= 0x08; /* Enable looping */ + restore_flags(flags); + } + for (chn = 0; chn < gus_audio_channels; chn++) + { + save_flags(flags); + cli(); + gus_select_voice(chn); + gus_write8(0x0d, ramp_mode[chn]); + if (iw_mode) + gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */ + gus_voice_on(mode[chn]); + restore_flags(flags); + } pcm_active = 1; } -static void -gus_transfer_output_block(int dev, unsigned long buf, +static void gus_transfer_output_block(int dev, unsigned long buf, int total_count, int intrflag, int chn) { /* @@ -2454,10 +2402,10 @@ * right data to the area pointed by gus_page_size. */ - int this_one, count; - unsigned long flags; - unsigned char dma_command; - unsigned long address, hold_address; + int this_one, count; + unsigned long flags; + unsigned char dma_command; + unsigned long address, hold_address; save_flags(flags); cli(); @@ -2465,15 +2413,16 @@ count = total_count / gus_audio_channels; if (chn == 0) - { - if (pcm_qlen >= pcm_nblk) - printk("GUS Warning: PCM buffers out of sync\n"); - - this_one = pcm_current_block = pcm_tail; - pcm_qlen++; - pcm_tail = (pcm_tail + 1) % pcm_nblk; - pcm_datasize[this_one] = count; - } else + { + if (pcm_qlen >= pcm_nblk) + printk(KERN_WARNING "GUS Warning: PCM buffers out of sync\n"); + + this_one = pcm_current_block = pcm_tail; + pcm_qlen++; + pcm_tail = (pcm_tail + 1) % pcm_nblk; + pcm_datasize[this_one] = count; + } + else this_one = pcm_current_block; gus_write8(0x41, 0); /* Disable GF1 DMA */ @@ -2483,12 +2432,12 @@ address += chn * pcm_banksize; if (audio_devs[dev]->dmap_out->dma > 3) - { - hold_address = address; - address = address >> 1; - address &= 0x0001ffffL; - address |= (hold_address & 0x000c0000L); - } + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */ dma_command = 0x21; /* IRQ enable, DMA start */ @@ -2504,62 +2453,60 @@ gus_write8(0x41, dma_command); /* Kick start */ if (chn == (gus_audio_channels - 1)) /* Last channel */ - { - /* - * Last (right or mono) channel data - */ - dma_active = 1; /* DMA started. There is a unacknowledged buffer */ - active_device = GUS_DEV_PCM_DONE; - if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) - { - play_next_pcm_block(); - } - } else - { - /* - * Left channel data. The right channel - * is transferred after DMA interrupt - */ - active_device = GUS_DEV_PCM_CONTINUE; - } + { + /* + * Last (right or mono) channel data + */ + dma_active = 1; /* DMA started. There is a unacknowledged buffer */ + active_device = GUS_DEV_PCM_DONE; + if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize)) + { + play_next_pcm_block(); + } + } + else + { + /* + * Left channel data. The right channel + * is transferred after DMA interrupt + */ + active_device = GUS_DEV_PCM_CONTINUE; + } restore_flags(flags); } -static void -gus_uninterleave8(char *buf, int l) +static void gus_uninterleave8(char *buf, int l) { /* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - char *buf2 = buf + halfsize, *src = bounce_buf; + int i, p = 0, halfsize = l / 2; + char *buf2 = buf + halfsize, *src = bounce_buf; memcpy(bounce_buf, buf, l); for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } } -static void -gus_uninterleave16(short *buf, int l) +static void gus_uninterleave16(short *buf, int l) { /* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */ - int i, p = 0, halfsize = l / 2; - short *buf2 = buf + halfsize, *src = (short *) bounce_buf; + int i, p = 0, halfsize = l / 2; + short *buf2 = buf + halfsize, *src = (short *) bounce_buf; memcpy(bounce_buf, (char *) buf, l * 2); for (i = 0; i < halfsize; i++) - { - buf[i] = src[p++]; /* Left channel */ - buf2[i] = src[p++]; /* Right channel */ - } + { + buf[i] = src[p++]; /* Left channel */ + buf2[i] = src[p++]; /* Right channel */ + } } -static void -gus_audio_output_block(int dev, unsigned long buf, int total_count, +static void gus_audio_output_block(int dev, unsigned long buf, int total_count, int intrflag) { struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; @@ -2571,29 +2518,27 @@ pcm_current_intrflag = intrflag; pcm_current_dev = dev; if (gus_audio_channels == 2) - { - char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); + { + char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys); - if (gus_audio_bits == 8) - gus_uninterleave8(b, total_count); - else - gus_uninterleave16((short *) b, total_count / 2); - } + if (gus_audio_bits == 8) + gus_uninterleave8(b, total_count); + else + gus_uninterleave16((short *) b, total_count / 2); + } gus_transfer_output_block(dev, buf, total_count, intrflag, 0); } -static void -gus_audio_start_input(int dev, unsigned long buf, int count, +static void gus_audio_start_input(int dev, unsigned long buf, int count, int intrflag) { - unsigned long flags; - unsigned char mode; + unsigned long flags; + unsigned char mode; save_flags(flags); cli(); DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ); - mode = 0xa0; /* DMA IRQ enabled, invert MSB */ if (audio_devs[dev]->dmap_in->dma > 3) @@ -2603,14 +2548,12 @@ mode |= 0x01; /* DMA enable */ gus_write8(0x49, mode); - restore_flags(flags); } -static int -gus_audio_prepare_for_input(int dev, int bsize, int bcount) +static int gus_audio_prepare_for_input(int dev, int bsize, int bcount) { - unsigned int rate; + unsigned int rate; gus_audio_bsize = bsize; audio_devs[dev]->dmap_in->flags |= DMA_NODMA; @@ -2619,19 +2562,18 @@ gus_write8(0x48, rate & 0xff); /* Set sampling rate */ if (gus_audio_bits != 8) - { - printk("GUS Error: 16 bit recording not supported\n"); - return -EINVAL; - } + { +/* printk("GUS Error: 16 bit recording not supported\n");*/ + return -EINVAL; + } return 0; } -static int -gus_audio_prepare_for_output(int dev, int bsize, int bcount) +static int gus_audio_prepare_for_output(int dev, int bsize, int bcount) { - int i; + int i; - long mem_ptr, mem_size; + long mem_ptr, mem_size; audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT; mem_ptr = 0; @@ -2655,12 +2597,10 @@ if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024)) pcm_nblk--; gus_write8(0x41, 0); /* Disable GF1 DMA */ - return 0; } -static int -gus_local_qlen(int dev) +static int gus_local_qlen(int dev) { return pcm_qlen; } @@ -2680,20 +2620,14 @@ NULL }; -static void -guswave_setup_voice(int dev, int voice, int chn) +static void guswave_setup_voice(int dev, int voice, int chn) { - struct channel_info *info = - &synth_devs[dev]->chn_info[chn]; + struct channel_info *info = &synth_devs[dev]->chn_info[chn]; guswave_set_instr(dev, voice, info->pgm_num); - - voices[voice].expression_vol = - info->controllers[CTL_EXPRESSION]; /* Just MSB */ - voices[voice].main_vol = - (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; - voices[voice].panning = - (info->controllers[CTL_PAN] * 2) - 128; + voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */ + voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; + voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; voices[voice].bender = 0; voices[voice].bender_range = info->bender_range; @@ -2701,15 +2635,13 @@ voices[voice].fixed_pitch = 1; } -static void -guswave_bender(int dev, int voice, int value) +static void guswave_bender(int dev, int voice, int value) { - int freq; + int freq; unsigned long flags; voices[voice].bender = value - 8192; - freq = compute_finetune(voices[voice].orig_freq, value - 8192, - voices[voice].bender_range, 0); + freq = compute_finetune(voices[voice].orig_freq, value - 8192, voices[voice].bender_range, 0); voices[voice].current_freq = freq; save_flags(flags); @@ -2719,45 +2651,43 @@ restore_flags(flags); } -static int -guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) +static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc) { - int i, p, best = -1, best_time = 0x7fffffff; + int i, p, best = -1, best_time = 0x7fffffff; p = alloc->ptr; /* - * First look for a completely stopped voice + * First look for a completely stopped voice */ for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0) - { - alloc->ptr = p; - return p; - } - if (alloc->alloc_times[p] < best_time) - { - best = p; - best_time = alloc->alloc_times[p]; - } - p = (p + 1) % alloc->max_voice; - } + { + if (alloc->map[p] == 0) + { + alloc->ptr = p; + return p; + } + if (alloc->alloc_times[p] < best_time) + { + best = p; + best_time = alloc->alloc_times[p]; + } + p = (p + 1) % alloc->max_voice; + } /* - * Then look for a releasing voice + * Then look for a releasing voice */ for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0xffff) - { - alloc->ptr = p; - return p; - } - p = (p + 1) % alloc->max_voice; - } - + { + if (alloc->map[p] == 0xffff) + { + alloc->ptr = p; + return p; + } + p = (p + 1) % alloc->max_voice; + } if (best >= 0) p = best; @@ -2790,11 +2720,10 @@ guswave_setup_voice }; -static void -set_input_volumes(void) +static void set_input_volumes(void) { - unsigned long flags; - unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ + unsigned long flags; + unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ if (have_gus_max) /* Don't disturb GUS MAX */ return; @@ -2813,15 +2742,15 @@ mask |= 0x04; if (recording_active) - { - /* - * Disable channel, if not selected for recording - */ - if (!(gus_recmask & SOUND_MASK_LINE)) - mask |= 0x01; - if (!(gus_recmask & SOUND_MASK_MIC)) - mask &= ~0x04; - } + { + /* + * Disable channel, if not selected for recording + */ + if (!(gus_recmask & SOUND_MASK_LINE)) + mask |= 0x01; + if (!(gus_recmask & SOUND_MASK_MIC)) + mask &= ~0x04; + } mix_image &= ~0x07; mix_image |= mask & 0x07; outb((mix_image), u_Mixer); @@ -2842,115 +2771,119 @@ if (!access_ok(VERIFY_WRITE, (int *)arg, sizeof(int))) return -EFAULT; - if (_SIOC_DIR(cmd) & _SIOC_WRITE) { + if (_SIOC_DIR(cmd) & _SIOC_WRITE) + { if (__get_user(val, (int *) arg)) return -EFAULT; - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - gus_recmask = val & MIX_DEVS; - if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) - gus_recmask = SOUND_MASK_MIC; - /* Note! Input volumes are updated during next open for recording */ - val = gus_recmask; - break; - - case SOUND_MIXER_MIC: - vol = val & 0xff; - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_mic_vol = vol; - set_input_volumes(); - val = vol | (vol << 8); - break; + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + gus_recmask = val & MIX_DEVS; + if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) + gus_recmask = SOUND_MASK_MIC; + /* Note! Input volumes are updated during next open for recording */ + val = gus_recmask; + break; + + case SOUND_MIXER_MIC: + vol = val & 0xff; + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_mic_vol = vol; + set_input_volumes(); + val = vol | (vol << 8); + break; - case SOUND_MIXER_LINE: - vol = val & 0xff; - if (vol < 0) - vol = 0; - if (vol > 100) - vol = 100; - gus_line_vol = vol; - set_input_volumes(); - val = vol | (vol << 8); - break; - - case SOUND_MIXER_PCM: - gus_pcm_volume = val & 0xff; - if (gus_pcm_volume < 0) - gus_pcm_volume = 0; - if (gus_pcm_volume > 100) - gus_pcm_volume = 100; - gus_audio_update_volume(); - val = gus_pcm_volume | (gus_pcm_volume << 8); - break; - - case SOUND_MIXER_SYNTH: - gus_wave_volume = val & 0xff; - if (gus_wave_volume < 0) - gus_wave_volume = 0; - if (gus_wave_volume > 100) - gus_wave_volume = 100; - if (active_device == GUS_DEV_WAVE) { - int voice; - for (voice = 0; voice < nr_voices; voice++) + case SOUND_MIXER_LINE: + vol = val & 0xff; + if (vol < 0) + vol = 0; + if (vol > 100) + vol = 100; + gus_line_vol = vol; + set_input_volumes(); + val = vol | (vol << 8); + break; + + case SOUND_MIXER_PCM: + gus_pcm_volume = val & 0xff; + if (gus_pcm_volume < 0) + gus_pcm_volume = 0; + if (gus_pcm_volume > 100) + gus_pcm_volume = 100; + gus_audio_update_volume(); + val = gus_pcm_volume | (gus_pcm_volume << 8); + break; + + case SOUND_MIXER_SYNTH: + gus_wave_volume = val & 0xff; + if (gus_wave_volume < 0) + gus_wave_volume = 0; + if (gus_wave_volume > 100) + gus_wave_volume = 100; + if (active_device == GUS_DEV_WAVE) + { + int voice; + for (voice = 0; voice < nr_voices; voice++) dynamic_volume_change(voice); /* Apply the new vol */ - } - val = gus_wave_volume | (gus_wave_volume << 8); - break; + } + val = gus_wave_volume | (gus_wave_volume << 8); + break; - default: - return -EINVAL; + default: + return -EINVAL; } - - } else { - switch (cmd & 0xff) { - /* - * Return parameters - */ - case SOUND_MIXER_RECSRC: - val = gus_recmask; - break; + } + else + { + switch (cmd & 0xff) + { + /* + * Return parameters + */ + case SOUND_MIXER_RECSRC: + val = gus_recmask; + break; - case SOUND_MIXER_DEVMASK: - val = MIX_DEVS; - break; - - case SOUND_MIXER_STEREODEVS: - val = 0; - break; - - case SOUND_MIXER_RECMASK: - val = SOUND_MASK_MIC | SOUND_MASK_LINE; - break; - - case SOUND_MIXER_CAPS: - val = 0; - break; - - case SOUND_MIXER_MIC: - val = gus_mic_vol | (gus_mic_vol << 8); - break; + case SOUND_MIXER_DEVMASK: + val = MIX_DEVS; + break; + + case SOUND_MIXER_STEREODEVS: + val = 0; + break; + + case SOUND_MIXER_RECMASK: + val = SOUND_MASK_MIC | SOUND_MASK_LINE; + break; + + case SOUND_MIXER_CAPS: + val = 0; + break; + + case SOUND_MIXER_MIC: + val = gus_mic_vol | (gus_mic_vol << 8); + break; + + case SOUND_MIXER_LINE: + val = gus_line_vol | (gus_line_vol << 8); + break; + + case SOUND_MIXER_PCM: + val = gus_pcm_volume | (gus_pcm_volume << 8); + break; + + case SOUND_MIXER_SYNTH: + val = gus_wave_volume | (gus_wave_volume << 8); + break; - case SOUND_MIXER_LINE: - val = gus_line_vol | (gus_line_vol << 8); - break; - - case SOUND_MIXER_PCM: - val = gus_pcm_volume | (gus_pcm_volume << 8); - break; - - case SOUND_MIXER_SYNTH: - val = gus_wave_volume | (gus_wave_volume << 8); - break; - - default: - return -EINVAL; + default: + return -EINVAL; } } - return __put_user(val, (int *)arg); } @@ -2961,43 +2894,42 @@ gus_default_mixer_ioctl }; -static int -gus_default_mixer_init(void) +static int gus_default_mixer_init(void) { - int n; + int n; if ((n = sound_alloc_mixerdev()) != -1) - { /* - * Don't install if there is another - * mixer - */ - mixer_devs[n] = &gus_mixer_operations; - } + { + /* + * Don't install if there is another + * mixer + */ + mixer_devs[n] = &gus_mixer_operations; + } if (have_gus_max) - { -/* - * Enable all mixer channels on the GF1 side. Otherwise recording will - * not be possible using GUS MAX. - */ - mix_image &= ~0x07; - mix_image |= 0x04; /* All channels enabled */ - outb((mix_image), u_Mixer); - } + { + /* + * Enable all mixer channels on the GF1 side. Otherwise recording will + * not be possible using GUS MAX. + */ + mix_image &= ~0x07; + mix_image |= 0x04; /* All channels enabled */ + outb((mix_image), u_Mixer); + } return n; } void gus_wave_init(struct address_info *hw_config) { - unsigned long flags; - unsigned char val; - char *model_num = "2.4"; - char tmp[64], tmp2[64]; - int gus_type = 0x24; /* 2.4 */ - - int irq = hw_config->irq, dma = hw_config->dma, - dma2 = hw_config->dma2; - int dev; - int sdev; + unsigned long flags; + unsigned char val; + char *model_num = "2.4"; + char tmp[64], tmp2[64]; + int gus_type = 0x24; /* 2.4 */ + + int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2; + int dev; + int sdev; hw_config->slots[0] = -1; /* No wave */ hw_config->slots[1] = -1; /* No ad1848 */ @@ -3008,14 +2940,14 @@ { if (irq < 0 || irq > 15) { - printk("ERROR! Invalid IRQ#%d. GUS Disabled", irq); + printk(KERN_ERR "ERROR! Invalid IRQ#%d. GUS Disabled", irq); return; } } if (dma < 0 || dma > 7 || dma == 4) { - printk("ERROR! Invalid DMA#%d. GUS Disabled", dma); + printk(KERN_ERR "ERROR! Invalid DMA#%d. GUS Disabled", dma); return; } gus_irq = irq; @@ -3046,7 +2978,7 @@ /* * It has the digital ASIC so the card is at least v3.4. * Next try to detect the true model. - */ + */ if (gus_pnp_flag) /* Hack hack hack */ val = 10; @@ -3124,9 +3056,9 @@ } } else - printk(KERN_WARNING "[Where's the CS4231?]"); + printk(KERN_WARNING "GUS: No CS4231 ??"); #else - printk("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n"); + printk(KERN_ERR "GUS MAX found, but not compiled in\n"); #endif } } @@ -3260,7 +3192,7 @@ if (hw_config->slots[4] != -1) sound_unload_audiodev(hw_config->slots[4]); if (hw_config->slots[5] != -1) - sound_unload_mixerdev(hw_config->slots[4]); + sound_unload_mixerdev(hw_config->slots[5]); if(samples) vfree(samples); @@ -3291,78 +3223,77 @@ parm = voices[voice].loop_irq_parm; switch (mode) - { + { + case LMODE_FINISH: /* + * Final loop finished, shoot volume down + */ - case LMODE_FINISH: /* - * Final loop finished, shoot volume down - */ + if ((int) (gus_read16(0x09) >> 4) < 100) /* + * Get current volume + */ + { + gus_voice_off(); + gus_rampoff(); + gus_voice_init(voice); + break; + } + gus_ramp_range(65, 4065); + gus_ramp_rate(0, 63); /* + * Fastest possible rate + */ + gus_rampon(0x20 | 0x40); /* + * Ramp down, once, irq + */ + voices[voice].volume_irq_mode = VMODE_HALT; + break; - if ((int) (gus_read16(0x09) >> 4) < 100) /* - * Get current volume - */ - { - gus_voice_off(); - gus_rampoff(); - gus_voice_init(voice); - break; - } - gus_ramp_range(65, 4065); - gus_ramp_rate(0, 63); /* - * Fastest possible rate - */ - gus_rampon(0x20 | 0x40); /* - * Ramp down, once, irq - */ - voices[voice].volume_irq_mode = VMODE_HALT; - break; - - case LMODE_PCM_STOP: - pcm_active = 0; /* Signal to the play_next_pcm_block routine */ - case LMODE_PCM: - { - - pcm_qlen--; - pcm_head = (pcm_head + 1) % pcm_nblk; - if (pcm_qlen && pcm_active) - { - play_next_pcm_block(); - } else - { /* Underrun. Just stop the voice */ - gus_select_voice(0); /* Left channel */ - gus_voice_off(); - gus_rampoff(); - gus_select_voice(1); /* Right channel */ - gus_voice_off(); - gus_rampoff(); - pcm_active = 0; - } - - /* - * If the queue was full before this interrupt, the DMA transfer was - * suspended. Let it continue now. - */ - if (audio_devs[gus_devnum]->dmap_out->qlen > 0) - DMAbuf_outputintr(gus_devnum, 0); - } - break; + case LMODE_PCM_STOP: + pcm_active = 0; /* Signal to the play_next_pcm_block routine */ + case LMODE_PCM: + { + pcm_qlen--; + pcm_head = (pcm_head + 1) % pcm_nblk; + if (pcm_qlen && pcm_active) + { + play_next_pcm_block(); + } + else + { + /* Underrun. Just stop the voice */ + gus_select_voice(0); /* Left channel */ + gus_voice_off(); + gus_rampoff(); + gus_select_voice(1); /* Right channel */ + gus_voice_off(); + gus_rampoff(); + pcm_active = 0; + } - default:; - } + /* + * If the queue was full before this interrupt, the DMA transfer was + * suspended. Let it continue now. + */ + + if (audio_devs[gus_devnum]->dmap_out->qlen > 0) + DMAbuf_outputintr(gus_devnum, 0); + } + break; + + default: + } restore_flags(flags); } -static void -do_volume_irq(int voice) +static void do_volume_irq(int voice) { - unsigned char tmp; - int mode, parm; - unsigned long flags; + unsigned char tmp; + int mode, parm; + unsigned long flags; save_flags(flags); cli(); gus_select_voice(voice); - tmp = gus_read8(0x0d); tmp &= ~0x20; /* * Disable volume ramp IRQ @@ -3374,138 +3305,132 @@ parm = voices[vo--- transfer too big, truncated ---