diff -u --recursive --new-file v2.1.125/linux/CREDITS linux/CREDITS --- v2.1.125/linux/CREDITS Fri Oct 9 13:27:04 1998 +++ linux/CREDITS Sun Oct 11 10:14:26 1998 @@ -1304,7 +1304,7 @@ S: USA N: Johan Myreen -E: jem@vipunen.hut.fi +E: jem@iki.fi D: PS/2 mouse driver writer etc. S: Dragonvagen 1 A 13 S: FIN-00330 Helsingfors @@ -1852,6 +1852,18 @@ S: 90491 Nuernberg S: Germany +N: Geert Uytterhoeven +E: geert@linux-m68k.org +W: http://www.cs.kuleuven.ac.be/~geert/ +P: 1024/EC4A1EE1 8B 88 38 35 88 1E 95 A1 CD 9E AE DC 4B 4A 2F 41 +D: m68k/Amiga and PPC/CHRP Longtrail coordinator +D: Frame buffer device and XF68_FBDev maintainer +D: m68k IDE maintainer +D: Amiga Zorro maintainer +S: C. Huysmansstraat 12 +S: B-3128 Baal +S: Belgium + N: Petr Vandrovec E: vandrove@vc.cvut.cz D: Small contributions to ncpfs @@ -1991,14 +2003,15 @@ S: The Netherlands N: David Woodhouse +E: Dave@mvhi.com 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: 29, David Bull Way +S: Milton, Cambridge. CB4 6DP S: England N: Frank Xia diff -u --recursive --new-file v2.1.125/linux/Documentation/Changes linux/Documentation/Changes --- v2.1.125/linux/Documentation/Changes Mon Oct 5 13:13:34 1998 +++ linux/Documentation/Changes Sat Oct 10 09:27:55 1998 @@ -33,7 +33,7 @@ Also, don't forget http://www.linuxhq.com/ for all your Linux kernel needs. -Last updated: September 3, 1998 +Last updated: October 9, 1998 Current Author: Chris Ricker (kaboom@gatech.edu or chris.ricker@m.cc.utah.edu). Current Minimal Requirements @@ -43,13 +43,14 @@ encountered a bug! If you're unsure what version you're currently running, the suggested command should tell you. -- Kernel modules 2.1.85 ; insmod -V +- Kernel modules 2.1.121 ; insmod -V - Gnu C 2.7.2.3 ; gcc --version - Binutils 2.8.1.0.23 ; ld -v -- Linux C Library 5.4.46 ; ls -l /lib/libc.so.* +- Linux libc5 C Library 5.4.46 ; ls -l /lib/libc.so.* +- Linux libc6 C Library 2.0.7pre6 ; ls -l /lib/libc.so.* - Dynamic Linker (ld.so) 1.9.9 ; ldd --version or ldd -v - Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.* -- Procps 1.2.8 ; ps --version +- Procps 1.2.9 ; ps --version - Procinfo 14 ; procinfo -v - Psmisc 17 ; pstree -V - Mount 2.7l ; mount --version @@ -57,7 +58,7 @@ - Loadlin 1.6a - Sh-utils 1.16 ; basename --v - Autofs 0.3.11 ; automount --version -- NFS 0.4.21 ; showmount --version +- NFS 2.2beta37 ; showmount --version - Bash 1.14.7 ; bash -version - Ncpfs 2.2.0 ; ncpmount -v - Pcmcia-cs 3.0.5 ; cardmgr -V @@ -114,8 +115,8 @@ more information, see the files in Documentation/fb/ ; you may also need to download the fbset utilities. -Libc -==== +Libc (libc5) +============ Linux-2.1.x is ELF-only. You can still compile a.out apps if you really want, but your kernel must be compiled ELF. If you can't @@ -144,11 +145,25 @@ accompanying release notes. The section about it breaking make is not a joke. +GNU libc (libc6) +================ + + Older versions of GNU libc (libc6) have a bug in the dynamic linker. +/etc/ld.so.cache gets mapped into memory and is never unmapped. If one +of your boot scripts calls ldconfig, /etc/ld.so.cache is deleted. Init, +however, still references that file; as of 2.1.122, the kernel will +consequently not be able to remount the root file system r/o at system +shutdown. To fix this, upgrade to at least the pre6 release of GNU +libc 2.0.7. As a temporary workaround, modify your boot scripts to do +the following before calling ldconfig: + + ln -f /etc/ld.so.cache /etc/ld.so.cache.old + Modules ======= - 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. + You need to upgrade to the latest version of modutils-2.1.x for +development kernels. 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 @@ -222,12 +237,12 @@ features like IPv6. As of 2.1.102, the IP firewalling code has been replaced; ipfwadm -will no longer work. You need to optain "ipchains," available from +will no longer work. You need to obtain "ipchains," available from http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html, and use that instead of ipfwadm. - To use port forwarding and auto forwarding you will need 'ipmasqadm' -tool, available from http://juanjox.home.ml.org. + To use port forwarding and auto forwarding you will need to obtain +"ipmasqadm," available from http://juanjox.home.ml.org/. Memory ====== @@ -281,6 +296,13 @@ /dev/lp0 with the new Plug-and-Play driver. If printing breaks with the new driver, try checking your lpd configuration. +Setserial +========= + + If you experience random problems (stuck lines, lost characters, +etc.) with serial lines under recent kernels, upgrading setserial +should help. + Syncookies ========== @@ -351,35 +373,28 @@ ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.23 ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23 -The 2.9.1.0.7 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.7-glibc.x86.tar.gz -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.7-libc5.x86.tar.gz -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.7.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.7-glibc.x86.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.7-libc5.x86.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.7.tar.gz +The 2.9.1.0.12 release: +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.12-glibc.x86.tar.gz +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.12-libc5.x86.tar.gz +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.12.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.12-glibc.x86.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.12-libc5.x86.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.12.tar.gz Installation notes: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.7 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.7 +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.12 +ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.12 Gnu C ===== -The 2.7.2.3 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/gcc-2.7.2.3.bin.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.3.bin.tar.gz +The egcs-1.0.3 release: +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-glibc.x86.tar.bz2 +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.3-libc5.x86.tar.bz2 +ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.3-glibc.x86.tar.bz2 +ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.3-libc5.x86.tar.bz2 Installation notes: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.gcc-2.7.2.3 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.gcc-2.7.2.3 - -The egcs-1.0.2 release: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.2-glibc.x86.tar.gz -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/egcs-1.0.2-libc5.x86.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.2-glibc.x86.tar.gz -ftp://sunsite.unc.edu/pub/Linux/GCC/egcs-1.0.2-libc5.x86.tar.gz -Installation notes: -ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.2 -ftp://sunsite.unc.edu/pub/Linux/GCC/release.egcs-1.0.2 +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.egcs-1.0.3 +ftp://sunsite.unc.edu/pub/Linux/GCC/release.egcs-1.0.3 Gnu C 2.7.2.3 source: ftp://prep.ai.mit.edu/pub/gnu/gcc-2.7.2.3.tar.gz @@ -388,13 +403,17 @@ Linux C Library =============== -The 5.4.46 release: +The (libc5) 5.4.46 release: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.46.bin.tar.gz ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.46.bin.tar.gz Installation notes for 5.4.46: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.46 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.46 +The (libc6) GNU libc 2.0.7pre6 release: +ftp://ftp.kernel.org/pub/software/libs/glibc/glibc-2.0.7pre6.tar.gz +ftp://ftp.kernel.org/pub/software/libs/glibc/glibc-2.0.7pre6.tar.bz2 + Linux C++ Library ================= @@ -415,15 +434,15 @@ Modules utilities ================= -The 2.1.85 release: -ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.85.tar.gz +The 2.1.121 release: +ftp://ftp.kernel.org/pub/linux/kernel/v2.1/modutils-2.1.121.tar.gz Procps utilities ================ The 1.2 release: -ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.8.tar.gz -ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.8.tgz +ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.2.9.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.2.9.tgz Procinfo utilities ================== @@ -454,8 +473,9 @@ DOSEMU ====== -The 0.66.7 release: -ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.66.7.tgz +The 0.98.1 release: +ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/dosemu-0.98.1.tgz +ftp://ftp.dosemu.org/dosemu/dosemu-0.98.1.tgz Loadlin ======= @@ -486,12 +506,13 @@ NFS === -The user-land 0.4.21 release: -ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz -ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz - -The kernel-level 8/30/98 release: -ftp://ftp.yggdrasil.com/private/hjl/knfsd-980830.tar.gz +The user-land 2.2beta37 release: +ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta37.tar.gz +ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/nfs-server-2.2beta37.tar.gz + +The kernel-level 9/30/98 release: +ftp://ftp.yggdrasil.com/private/hjl/knfsd-980930.tar.gz +ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-980930.tar.gz Net-tools ========= @@ -530,6 +551,13 @@ The 3.0.5 release: ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.5.tar.gz +Setserial +========= + +The 2.14 release: +ftp://tsx-11.mit.edu/pub/linux/sources/sbin/setserial-2.14.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/serial/setserial-2.14.tar.gz + PPP === @@ -545,6 +573,7 @@ IP Masq Adm =========== + The 0.4.1 release: http://juanjox.home.ml.org/ipmasqadm-0.4.1.tar.gz @@ -581,12 +610,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, as does Red Hat 5.0. +everything you need, and Red Hat 5.1 ships with most necessary software. 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. The -Debian 2.0 release should have most packages you need as well. +Debian 2.0 release ships with 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 diff -u --recursive --new-file v2.1.125/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.125/linux/Documentation/Configure.help Fri Oct 9 13:27:04 1998 +++ linux/Documentation/Configure.help Sun Oct 11 10:14:32 1998 @@ -1196,15 +1196,6 @@ Say Y here to enable support in the dumb serial driver to support the HUB6 card. -TGA Console Support -CONFIG_TGA_CONSOLE - Many Alpha systems (e.g the Multia) are shipped with a graphics card - that implements the TGA interface (much like the VGA standard, but - older TGA adapters are *not* VGA compatible). On such systems, you - should say Y here so that the TGA driver rather than the standard - VGA driver is used. Note that, at this time, there is no X server - for these systems. If unsure, try N. - PCI support CONFIG_PCI Find out whether you have a PCI motherboard. PCI is the name of a @@ -3217,6 +3208,16 @@ This is a backward compatibility option, choose Y for now. This option will be removed soon. +HIgh Performance Parallel Interface support (EXPERIMENTAL) +CONFIG_HIPPI + HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and + 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI + can run over copper (25m) or fiber (300m on multi-mode or 10km on + single-mode). If you are connected to a HIPPI network, and want + to enable HIPPI support in the kernel, say Y here (you must also + remember to enable the driver for your HIPPI card below). Most + people will say N here. + SCSI support? CONFIG_SCSI If you want to use a SCSI hard disk, SCSI tape drive, SCSI CDROM or @@ -5312,7 +5313,7 @@ This is yet another chipset driver for the COM90xx cards, but this time only using memory-mapped mode, and no IO ports at all. This driver is completely untested, so if you have one of these cards, - please mail dwmw2@cam.ac.uk, especially if it works! + please mail David.Woodhouse@mvhi.com, especially if it works! This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you @@ -8187,7 +8188,7 @@ say more than an occasional beep, by programming the PC speaker. Kernel patches and programs to do that are in the pcsndrv package on ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console/ and in the - pcsp patch at ftp://dwmw2.robinson.cam.ac.uk/pub/kernel/ . + pcsp patch at http://www.imladris.demon.co.uk/pcsp/ OSS sound modules CONFIG_SOUND_OSS @@ -9261,7 +9262,7 @@ Ariadne support CONFIG_ARIADNE - If you have a VillageTronics Ariadne Ethernet adapter, say Y. + If you have a Village Tronic Ariadne Ethernet adapter, say Y. Otherwise, say N. This driver is also available as a module ( = code which can be @@ -9271,7 +9272,7 @@ Ariadne II support CONFIG_ARIADNE2 - If you have a VillageTronics Ariadne II Ethernet adapter, say Y. + If you have a Village Tronic Ariadne II Ethernet adapter, say Y. Otherwise, say N. This driver is also available as a module ( = code which can be @@ -9745,6 +9746,46 @@ Say 'Y' here for ARM systems with the VIDC video controller and 16-bit Linear sound DACs. If unsure, say N. +Backward compatibility mode for Xpmac +CONFIG_FB_COMPAT_XPMAC + If you use the Xpmac X server (common with mklinux), you'll need + to enable this to use X. You should consider changing to XFree86 + which includes a server that supports the frame buffer device + directly (XF68_FBDev). + +Support for PowerMac keyboard +CONFIG_MAC_KEYBOARD + This option allows you to use an ADB keyboard attached to your + machine. Note that this disables any other (ie. PS/2) keyboard + support, even if your machine is physically capable of using both + at the same time. + + If you use an ADB keyboard (4 pin connector), say Y here. + If you use a PS/2 keyboard (6 pin connector), say N here. + +Support for PowerMac floppy +CONFIG_MAC_FLOPPY + If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple) + floppy controller, say Y here. Most commonly found in PowerMacs. + +Support for PowerMac serial ports +CONFIG_MAC_SERIAL + If you have Macintosh style serial ports (8 pin mini-DIN), this + is the driver for them. If you also have regular serial ports + and enable the driver for them, you can't currently use the + serial console feature. + +Support for PowerMac ADB mouse +CONFIG_ADBMOUSE + If you have an ADB mouse (4 pin connector) as is common on + Macintoshes, say Y here. + +Winbond SL82c105 support +CONFIG_BLK_DEV_SL82C105 + If you have a Winbond SL82c105 IDE controller, say Y here to + enable special configuration for this chip. This is common + on various CHRP motherboards, but could be used elsewhere. + If in doubt, say Y. # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DMA, FTP, Internet, Intel, IRQ, @@ -9853,7 +9894,7 @@ # LocalWords: INSNS Ataris AutoConfig ZORRO OCS AMIFB Agnus Denise ECS CDTV GB # LocalWords: AGA Cybervision CYBER GSP TMS DMI Zorro ACSI ROMs SLM BioNet GVP # LocalWords: PAMsNet TekMagic Cyberstorm MkI CYBERSTORMII MkII BLZ onboard cx -# LocalWords: VillageTronics ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB +# LocalWords: Village Tronic ATARILANCE RieblCard PAMCard VME MFP sangoma LAPB # LocalWords: Rhotron BioData's Multiface AMIGAMOUSE COPCON Amiga's bitplanes # LocalWords: ATARIMOUSE MFPSER SCC's MegaSTE ESCC Atari's GVPIOEXT DMASOUND # LocalWords: fdutils cisco univercd rpcg htm iface lapb LAPBETHER tpqic qic diff -u --recursive --new-file v2.1.125/linux/Documentation/powerpc/00-INDEX linux/Documentation/powerpc/00-INDEX --- v2.1.125/linux/Documentation/powerpc/00-INDEX Sat May 2 14:19:51 1998 +++ linux/Documentation/powerpc/00-INDEX Sat Oct 10 09:53:24 1998 @@ -11,4 +11,5 @@ - use and state info about Linux/PPC on MP machines sound.txt - info on sound support under Linux/PPC - +zImage_layout.txt + - info on the kernel images for Linux/PPC diff -u --recursive --new-file v2.1.125/linux/Documentation/powerpc/smp.txt linux/Documentation/powerpc/smp.txt --- v2.1.125/linux/Documentation/powerpc/smp.txt Thu Apr 23 20:21:27 1998 +++ linux/Documentation/powerpc/smp.txt Sat Oct 10 09:53:24 1998 @@ -5,7 +5,7 @@ (Cort Dougan, cort@cs.nmt.edu) please email me if you have questions, comments or corrections. -Last Change: 4.1.98 +Last Change: 10.8.98 SMP support for Linux/PPC is still in its early stages and likely to be buggy for a while. If you want to help by writing code or testing @@ -13,7 +13,7 @@ 1. State of Supported Hardware - PowerSurge Architecture - UMAX s900, Apple 9500/9600/8500/8600/7500/7600 + PowerSurge Architecture - tested on UMAX s900, Apple 9600 The second processor on this machine boots up just fine and enters its idle loop. Hopefully a completely working SMP kernel on this machine will be done shortly. @@ -22,7 +22,9 @@ necessary to work with any number would not be overly difficult but I don't have any machines with >2 processors so it's not high on my list of priorities. If anyone else would like do to the work email - me and I can point out the places that need changed. + me and I can point out the places that need changed. If you have >2 + processors and don't want to add support yourself let me know and I + can take a look into it. BeBox BeBox support hasn't been added to the 2.1.X kernels from 2.0.X diff -u --recursive --new-file v2.1.125/linux/Documentation/powerpc/sound.txt linux/Documentation/powerpc/sound.txt --- v2.1.125/linux/Documentation/powerpc/sound.txt Thu Apr 23 20:21:27 1998 +++ linux/Documentation/powerpc/sound.txt Sat Oct 10 09:53:24 1998 @@ -1,7 +1,7 @@ Information about PowerPC Sound support ===================================================================== -Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions, +Please mail me (Cort Dougan, cort@cs.nmt.edu) if you have questions, comments or corrections. Last Change: 3.24.98 diff -u --recursive --new-file v2.1.125/linux/Documentation/powerpc/zImage_layout.txt linux/Documentation/powerpc/zImage_layout.txt --- v2.1.125/linux/Documentation/powerpc/zImage_layout.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/powerpc/zImage_layout.txt Sat Oct 10 09:53:24 1998 @@ -0,0 +1,47 @@ + Information about the Linux/PPC kernel images +===================================================================== + +Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions, +comments or corrections. + +This document is meant to answer several questions I've had about how +the PReP system boots and how Linux/PPC interacts with that mechanism. +It would be nice if we could have information on how other architectures +boot here as well. If you have anything to contribute, please +let me know. + + +1. PReP boot file + + This is the file necessary to boot PReP systems from floppy or + hard drive. The firmware reads the PReP partition table entry + and will load the image accordingly. + + To boot the zImage, copy it onto a floppy with dd if=zImage of=/dev/fd0h1440 + or onto a PReP hard drive partition with dd if=zImage of=/dev/sda4 + assuming you've created a PReP partition (type 0x41) with fdisk on + /dev/sda4. + + The layout of the image format is: + + 0x0 +------------+ + | | PReP partition table entry + | | + 0x400 +------------+ + | | Bootstrap program code + data + | | + | | + +------------+ + | | compressed kernel, elf header removed + +------------+ + | | initrd (if loaded) + +------------+ + | | Elf section table for bootstrap program + +------------+ + + +2. MBX boot file + + The MBX boards can load an elf image, and relocate it to the + proper location in memory - it copies the image to the location it was + linked at. diff -u --recursive --new-file v2.1.125/linux/Documentation/sound/MultiSound linux/Documentation/sound/MultiSound --- v2.1.125/linux/Documentation/sound/MultiSound Tue Aug 18 22:02:01 1998 +++ linux/Documentation/sound/MultiSound Fri Oct 9 11:56:59 1998 @@ -1,180 +1,476 @@ -Getting Firmware -~~~~~~~~~~~~~~~~ - -See the end of this document on how to obtain and create the necessary -firmware files. - - -Supported Features -~~~~~~~~~~~~~~~~~~ - -Currently digital audio and mixer functionality is supported. (memory -mapped digital audio is not yet supported). Modular MultiSound -support is composed of the following modules: - -msnd - MultiSound base (requires soundcore) -msnd_classic - Base audio/mixer support for Classic, Monetery and - Tahiti cards -msnd_pinnacle - Base audio/mixer support for Pinnacle and Fiji cards - - -Important Notes - Read Before Using -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* The firmware files are not included (may change in future). You -must obtain these images from Turtle Beach (they are included in the -MultiSound Development Kits), and place them in /etc/sound for -example, and give the full paths in the Linux configuration. Please -note these files must be binary files, not assembler. - -* You need the following information to use this driver: the card's -I/O base (i.e. 0x250), the IRQ (i.e. 5), and the shared memory area -(i.e. 0xd8000). - -* Probing is not currently implemented, and only the msnd_classic -driver will actually program the card's IRQ and SMA locations; the -msnd_pinnacle is primarily for use with the card in PnP mode, however -it should work if you know what the card's resource values are (this -will change in the future). - -* Note the Turtle Beach Pinnacle card contains a Kurzweil MA-1 -synthesizer with an MPU compatible interface, which should work with -the mpu401 module. You must know the resource values of the MA-1. - - -Examples -~~~~~~~~ - -* If you have a MultiSound Classic/Monterey/Tahiti: - -insmod soundcore -insmod msnd -insmod msnd_classic io=0x290 irq=7 mem=0xd0000 - -* If you have a MultiSound Pinnacle: - -insmod soundcore -insmod msnd -insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000 - -* To use the MPU-compatible Kurzweil synth on the Pinnacle, add the -following: - -insmod sound -insmod mpu401 io=0x330 irq=9 - - -msnd_classic, msnd_pinnacle Required Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If the following options are not given, the module will not load. -Examine the kernel message log for informative error messages. -WARNING--probing isn't supported so try to make sure you have the -correct shared memory area, otherwise you may experience problems. - -io I/O base of DSP, e.g. io=0x210 -irq IRQ number, e.g. irq=5 -mem Shared memory area, e.g. mem=0xd8000 - - -msnd_classic, msnd_pinnacle Additional Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -fifosize The digital audio FIFOs, in kilobytes. The - default is 64kB (two FIFOs are allocated, so - this uses up 128kB). - -calibrate_signal Setting this to one calibrates the ADCs to the - signal, zero calibrates to the card (defaults - to zero). - - -msnd_pinnacle Additional Options -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -digital Specify digital=1 to enable the S/PDIF input - if you have the digital daughterboard - adapter. This will enable access to the - DIGITAL1 input for the soundcard in the mixer. - Some mixer programs might have trouble setting - the DIGITAL1 source as an input. If you have - trouble, you can try the setdigital.c program - at the bottom of this document. - - -Obtaining and Creating Firmware Files -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - For the Classic/Tahiti/Monterey - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Download to /tmp and unzip the following file from Turtle Beach: - - ftp://ftp.tbeach.com/pub/tbs/pinn/msndvkit.zip - -When unzipped, unzip the file named MsndFiles.zip. Then copy the -following firmware files to /etc/sound (note the file renaming): - - cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin - cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin - -When configuring the Linux kernel, specify /etc/sound/msndinit.bin and -/etc/sound/msndperm.bin for the two firmware files (Linux kernel -versions older than 2.2 do not ask for firmware paths, and are -hardcoded to /etc/sound). - - - For the Pinnacle/Fiji - ~~~~~~~~~~~~~~~~~~~~~ - -Download to /tmp and unzip the following file from Turtle Beach (be -sure to use the entire URL; some have had trouble navigating to the -URL): - - ftp://ftp.tbeach.com/oldpub/tbs/pinn/pnddk100.zip - -Put the following lines into a file named conv.l (between the start -and end lines): - --- conv.l start -- -%% -[ \n\t,\r] -\;.* -DB -[0-9A-Fa-f]+H { int n; sscanf(yytext, "%xH", &n); printf("%c", n); } --- conv.l end -- - -Then, compile the conv program with GNU make with the following -command: - - make LEX=flex LOADLIBES=-lfl conv - -This should give you an executable named conv. Now, we create the -binary firmware files by doing the following conversion (assuming the -archive unpacked into a directory named PINNDDK): - - ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin - ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin - -The conv (and conv.l) program is not needed after conversion and can -be safely deleted. Then, when configuring the Linux kernel, specify -/etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two -firmware files (Linux kernel versions older than 2.2 do not ask for -firmware paths, and are hardcoded to /etc/sound). - - -Recording from the S/PDIF Input -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you have a Pinnacle or Fiji with S/PDIF input and want to set it as -the input source, you can use this program if you have trouble trying -to do it with a mixer program (be sure to insert the module with the -digital=1 option). - -Compile with: -cc -O setdigital.c -o setdigital - --- start setdigital.c -- +#! /bin/sh +# +# Turtle Beach MultiSound Driver Notes +# -- Andrew Veliath +# +# Last update: September 10, 1998 +# Corresponding msnd driver: 0.8.2 +# +# ** This file is a README (top part) and shell archive (bottom part). +# The corresponding archived utility sources can be unpacked by +# running `sh MultiSound' (the utilities are only needed for the +# Pinnacle and Fiji cards). ** +# +# +# -=-=- Getting Firmware -=-=- +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# See the section `Obtaining and Creating Firmware Files' in this +# document for instructions on obtaining the necessary firmware +# files. +# +# +# Supported Features +# ~~~~~~~~~~~~~~~~~~ +# +# Currently, full-duplex digital audio (/dev/dsp only, /dev/audio is +# not currently available) and mixer functionality (/dev/mixer) are +# supported (memory mapped digital audio is not yet supported). +# Digital transfers and monitoring can be done as well if you have +# the digital daughterboard (see the section on using the S/PDIF port +# for more information). +# +# Support for the Turtle Beach MultiSound Hurricane architecture is +# composed of the following modules (these can also operate compiled +# into the kernel): +# +# msnd - MultiSound base (requires soundcore) +# +# msnd_classic - Base audio/mixer support for Classic, Monetery and +# Tahiti cards +# +# msnd_pinnacle - Base audio/mixer support for Pinnacle and Fiji cards +# +# +# Important Notes - Read Before Using +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# The firmware files are not included (may change in future). You +# must obtain these images from Turtle Beach (they are included in +# the MultiSound Development Kits), and place them in /etc/sound for +# example, and give the full paths in the Linux configuration. If +# you are compiling in support for the MultiSound driver rather than +# using it as a module, these firmware files must be accessible +# during kernel compilation. +# +# Please note these files must be binary files, not assembler. See +# the section later in this document for instructions to obtain these +# files. +# +# +# Configuring Card Resources +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# ** This section is very important, as your card may not work at all +# or your machine may crash if you do not do this correctly. ** +# +# * Classic/Monterey/Tahiti +# +# These cards are configured through the driver msnd_classic. You must +# know the io port, then the driver will select the irq and memory resources +# on the card. It is up to you to know if these are free locations or now, +# a conflict can lock the machine up. +# +# * Pinnacle/Fiji +# +# The Pinnacle and Fiji cards have an extra config port, either +# 0x250, 0x260 or 0x270. This port can be disabled to have the card +# configured strictly through PnP, however you lose the ability to +# access the IDE controller and joystick devices on this card when +# using PnP. The included pinnaclecfg program in this shell archive +# can be used to configure the card in non-PnP mode, and in PnP mode +# you can use isapnptools. These are described briefly here. +# +# pinnaclecfg is not required; you can use the msnd_pinnacle module +# to fully configure the card as well. However, pinnaclecfg can be +# used to change the resource values of a particular device after the +# msnd_pinnacle module has been loaded. If you are compiling the +# driver into the kernel, you must set these values during compile +# time, however other peripheral resource values can be changed with +# the pinnaclecfg program after the kernel is loaded. +# +# +# *** PnP mode +# +# Use pnpdump to obtain a sample configuration if you can; I was able +# to obtain one with the command `pnpdump 1 0x203' -- this may vary +# for you (running pnpdump by itself did not work for me). Then, +# edit this file and use isapnp to uncomment and set the card values. +# Use these values when inserting the msnd_pinnacle module. Using +# this method, you can set the resources for the DSP and the Kurzweil +# synth (Pinnacle). Since Linux does not directly support PnP +# devices, you may have difficulty when using the card in PnP mode +# when it the driver is compiled into the kernel. Using non-PnP mode +# is preferable in this case. +# +# Here is an example mypinnacle.conf for isapnp that sets the card to +# io base 0x210, irq 5 and mem 0xd8000, and also sets the Kurzweil +# synth to 0x330 and irq 9 (may need editing for your system): +# +# (READPORT 0x0203) +# (CSN 2) +# (IDENTIFY *) +# +# # DSP +# (CONFIGURE BVJ0440/-1 (LD 0 +# (INT 0 (IRQ 5 (MODE +E))) (IO 0 (BASE 0x0210)) (MEM 0 (BASE 0x0d8000)) +# (ACT Y))) +# +# # Kurzweil Synth (Pinnacle Only) +# (CONFIGURE BVJ0440/-1 (LD 1 +# (IO 0 (BASE 0x0330)) (INT 0 (IRQ 9 (MODE +E))) +# (ACT Y))) +# +# (WAITFORKEY) +# +# +# *** Non-PnP mode +# +# The second way is by running the card in non-PnP mode. This +# actually has some advantages in that you can access some other +# devices on the card, such as the joystick and IDE controller. To +# configure the card, unpack this shell archive and build the +# pinnaclecfg program. Using this program, you can assign the +# resource values to the card's devices, or disable the devices. As +# an alternative to using pinnaclecfg, you can specify many of the +# configuration values when loading the msnd_pinnacle module (or +# during kernel configuration when compiling the driver into the +# kernel). +# +# If you specify cfg=0x250 for the msnd_pinnacle module, it +# automatically configure the card to the given io, irq and memory +# values using that config port (the config port is jumper selectable +# on the card to 0x250, 0x260 or 0x270). +# +# See the `msnd_pinnacle Additional Options' section below for more +# information on these parameters (also, if you compile the driver +# directly into the kernel, these extra parameters can be useful +# here). +# +# +# ** It is very easy to cause problems in your machine if you choose a +# resource value which is incorrect. ** +# +# +# Examples +# ~~~~~~~~ +# +# * MultiSound Classic/Monterey/Tahiti: +# +# insmod soundcore +# insmod msnd +# insmod msnd_classic io=0x290 irq=7 mem=0xd0000 +# +# * MultiSound Pinnacle in PnP mode: +# +# insmod soundcore +# insmod msnd +# isapnp mypinnacle.conf +# insmod msnd_pinnacle io=0x210 irq=5 mem=0xd8000 <-- match mypinnacle.conf values +# +# * MultiSound Pinnacle in non-PnP mode (replace 0x250 with your configuration port, +# one of 0x250, 0x260 or 0x270): +# +# insmod soundcore +# insmod msnd +# insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 +# +# * To use the MPU-compatible Kurzweil synth on the Pinnacle in PnP +# mode, add the following (assumes you did `isapnp mypinnacle.conf'): +# +# insmod sound +# insmod mpu401 io=0x330 irq=9 <-- match mypinnacle.conf values +# +# * To use the MPU-compatible Kurzweil synth on the Pinnacle in non-PnP +# mode, add the following. Note how we first configure the peripheral's +# resources, _then_ install a Linux driver for it: +# +# insmod sound +# pinnaclecfg 0x250 mpu 0x330 9 +# insmod mpu401 io=0x330 irq=9 +# +# -- OR you can use the following sequence without pinnaclecfg in non-PnP mode: +# +# insmod soundcore +# insmod msnd +# insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 mpu_io=0x330 mpu_irq=9 +# insmod sound +# insmod mpu401 io=0x330 irq=9 +# +# * To setup the joystick port on the Pinnacle in non-PnP mode (though +# you have to find the actual Linux joystick driver elsewhere), you +# can use pinnaclecfg: +# +# pinnaclecfg 0x250 joystick 0x200 +# +# -- OR you can configure this using msnd_pinnacle with the following: +# +# insmod soundcore +# insmod msnd +# insmod msnd_pinnacle cfg=0x250 io=0x290 irq=5 mem=0xd0000 joystick_io=0x200 +# +# +# msnd_classic, msnd_pinnacle Required Options +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# If the following options are not given, the module will not load. +# Examine the kernel message log for informative error messages. +# WARNING--probing isn't supported so try to make sure you have the +# correct shared memory area, otherwise you may experience problems. +# +# io I/O base of DSP, e.g. io=0x210 +# irq IRQ number, e.g. irq=5 +# mem Shared memory area, e.g. mem=0xd8000 +# +# +# msnd_classic, msnd_pinnacle Additional Options +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# fifosize The digital audio FIFOs, in kilobytes. If not +# specified, the default will be used. Increasing +# this value will reduce the chance of a FIFO +# underflow at the expense of increasing overall +# latency. For example, fifosize=512 will +# allocate 512kB read and write FIFOs (1MB total). +# While this may reduce dropouts, a heavy machine +# load will undoubtedly starve the FIFO of data +# and you will eventually get dropouts. One +# option is to alter the scheduling priority of +# the playback process, using `nice' or some form +# of POSIX soft real-time scheduling. +# +# calibrate_signal Setting this to one calibrates the ADCs to the +# signal, zero calibrates to the card (defaults +# to zero). +# +# +# msnd_pinnacle Additional Options +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# digital Specify digital=1 to enable the S/PDIF input +# if you have the digital daughterboard +# adapter. This will enable access to the +# DIGITAL1 input for the soundcard in the mixer. +# Some mixer programs might have trouble setting +# the DIGITAL1 source as an input. If you have +# trouble, you can try the setdigital.c program +# at the bottom of this document. +# +# cfg Non-PnP configuration port for the Pinnacle +# and Fiji (typically 0x250, 0x260 or 0x270, +# depending on the jumper configuration). If +# this option is omitted, then it is assumed +# that the card is in PnP mode, and that the +# specified DSP resource values are already +# configured with PnP (i.e. it won't attempt to +# do any sort of configuration). +# +# When the Pinnacle is in non-PnP mode, you can use the following +# options to configure particular devices. If a full specification +# for a device is not given, then the device is not configured. Note +# that you still must use a Linux driver for any of these devices +# once their resources are setup (such as the Linux joystick driver, +# or the MPU401 driver from OSS for the Kurzweil synth). +# +# mpu_io I/O port of MPU (on-board Kurzweil synth) +# mpu_irq IRQ of MPU (on-board Kurzweil synth) +# ide_io0 First I/O port of IDE controller +# ide_io1 Second I/O port of IDE controller +# ide_irq IRQ IDE controller +# joystick_io I/O port of joystick +# +# +# Obtaining and Creating Firmware Files +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# For the Classic/Tahiti/Monterey +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Download to /tmp and unzip the following file from Turtle Beach: +# +# ftp://ftp.voyetra.com/pub/tbs/msndcl/msndvkit.zip +# +# When unzipped, unzip the file named MsndFiles.zip. Then copy the +# following firmware files to /etc/sound (note the file renaming): +# +# cp DSPCODE/MSNDINIT.BIN /etc/sound/msndinit.bin +# cp DSPCODE/MSNDPERM.REB /etc/sound/msndperm.bin +# +# When configuring the Linux kernel, specify /etc/sound/msndinit.bin and +# /etc/sound/msndperm.bin for the two firmware files (Linux kernel +# versions older than 2.2 do not ask for firmware paths, and are +# hardcoded to /etc/sound). +# +# If you are compiling the driver into the kernel, these files must +# be accessible during compilation, but will not be needed later. +# The files must remain, however, if the driver is used as a module. +# +# +# For the Pinnacle/Fiji +# ~~~~~~~~~~~~~~~~~~~~~ +# +# Download to /tmp and unzip the following file from Turtle Beach (be +# sure to use the entire URL; some have had trouble navigating to the +# URL): +# +# ftp://ftp.voyetra.com/pub/tbs/pinn/pnddk100.zip +# +# Unpack this shell archive, and run make in the created directory +# (you need a C compiler and flex to build the utilities). This +# should give you the executables conv, pinnaclecfg and setdigital. +# conv is only used temporarily here to create the firmware files, +# while pinnaclecfg is used to configure the Pinnacle or Fiji card in +# non-PnP mode, and setdigital can be used to set the S/PDIF input on +# the mixer (pinnaclecfg and setdigital should be copied to a +# convenient place, possibly run during system initialization). +# +# To generating the firmware files with the `conv' program, we create +# the binary firmware files by doing the following conversion +# (assuming the archive unpacked into a directory named PINNDDK): +# +# ./conv < PINNDDK/dspcode/pndspini.asm > /etc/sound/pndspini.bin +# ./conv < PINNDDK/dspcode/pndsperm.asm > /etc/sound/pndsperm.bin +# +# The conv (and conv.l) program is not needed after conversion and can +# be safely deleted. Then, when configuring the Linux kernel, specify +# /etc/sound/pndspini.bin and /etc/sound/pndsperm.bin for the two +# firmware files (Linux kernel versions older than 2.2 do not ask for +# firmware paths, and are hardcoded to /etc/sound). +# +# If you are compiling the driver into the kernel, these files must +# be accessible during compilation, but will not be needed later. +# The files must remain, however, if the driver is used as a module. +# +# +# Using Digital I/O with the S/PDIF Port +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# If you have a Pinnacle or Fiji with the digital daughterboard and +# want to set it as the input source, you can use this program if you +# have trouble trying to do it with a mixer program (be sure to +# insert the module with the digital=1 option, or say Y to the option +# during compiled-in kernel operation). Upon selection of the S/PDIF +# port, you should be able monitor and record from it. +# +# There is something to note about using the S/PDIF port. Digital +# timing is taken from the digital signal, so if a signal is not +# connected to the port and it is selected as recording input, you +# will find PCM playback to be distorted in playback rate. Also, +# attempting to record at a sampling rate other than the DAT rate may +# be problematic (i.e. trying to record at 8000Hz when the DAT signal +# is 44100Hz). If you have a problem with this, set the recording +# input to the line in if you need to record at a rate other than +# that of the DAT rate. +# +# +# -- Shell archive attached below, just run `sh MultiSound' to extract. +# Contains Pinnacle/Fiji utilities to convert firmware, configure +# in non-PnP mode, and select the DIGITAL1 input for the mixer. +# +# +#!/bin/sh +# This is a shell archive (produced by GNU sharutils 4.2). +# To extract the files from this archive, save it to some FILE, remove +# everything before the `!/bin/sh' line above, then type `sh FILE'. +# +# Made on 1998-09-05 08:26 EDT by . +# Source directory was `/home/andrewtv/programming/pinnacle/pinnacle'. +# +# Existing files will *not* be overwritten unless `-c' is specified. +# +# This shar contains: +# length mode name +# ------ ---------- ------------------------------------------ +# 2111 -rw-rw-r-- MultiSound.d/setdigital.c +# 10301 -rw-rw-r-- MultiSound.d/pinnaclecfg.c +# 96 -rw-rw-r-- MultiSound.d/Makefile +# 141 -rw-rw-r-- MultiSound.d/conv.l +# +save_IFS="${IFS}" +IFS="${IFS}:" +gettext_dir=FAILED +locale_dir=FAILED +first_param="$1" +for dir in $PATH +do + if test "$gettext_dir" = FAILED && test -f $dir/gettext \ + && ($dir/gettext --version >/dev/null 2>&1) + then + set `$dir/gettext --version 2>&1` + if test "$3" = GNU + then + gettext_dir=$dir + fi + fi + if test "$locale_dir" = FAILED && test -f $dir/shar \ + && ($dir/shar --print-text-domain-dir >/dev/null 2>&1) + then + locale_dir=`$dir/shar --print-text-domain-dir` + fi +done +IFS="$save_IFS" +if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED +then + echo=echo +else + TEXTDOMAINDIR=$locale_dir + export TEXTDOMAINDIR + TEXTDOMAIN=sharutils + export TEXTDOMAIN + echo="$gettext_dir/gettext -s" +fi +touch -am 1231235999 $$.touch >/dev/null 2>&1 +if test ! -f 1231235999 && test -f $$.touch; then + shar_touch=touch +else + shar_touch=: + echo + $echo 'WARNING: not restoring timestamps. Consider getting and' + $echo "installing GNU \`touch', distributed in GNU File Utilities..." + echo +fi +rm -f 1231235999 $$.touch +# +if mkdir _sh21233; then + $echo 'x -' 'creating lock directory' +else + $echo 'failed to create lock directory' + exit 1 +fi +# ============= MultiSound.d/setdigital.c ============== +if test ! -d 'MultiSound.d'; then + $echo 'x -' 'creating directory' 'MultiSound.d' + mkdir 'MultiSound.d' +fi +if test -f 'MultiSound.d/setdigital.c' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/setdigital.c' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/setdigital.c' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/setdigital.c' && +/********************************************************************* +X * +X * setdigital.c - sets the DIGITAL1 input for a mixer +X * +X * Copyright (C) 1998 Andrew Veliath +X * +X * This program is free software; you can redistribute it and/or modify +X * it under the terms of the GNU General Public License as published by +X * the Free Software Foundation; either version 2 of the License, or +X * (at your option) any later version. +X * +X * This program is distributed in the hope that it will be useful, +X * but WITHOUT ANY WARRANTY; without even the implied warranty of +X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +X * GNU General Public License for more details. +X * +X * You should have received a copy of the GNU General Public License +X * along with this program; if not, write to the Free Software +X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +X * +X * $Id: setdigital.c,v 1.1 1998/08/29 03:32:33 andrewtv Exp $ +X * +X ********************************************************************/ +X #include #include #include @@ -182,53 +478,586 @@ #include #include #include - +X +int main(int argc, char *argv[]) +{ +X int fd; +X unsigned long recmask, recsrc; +X +X if (argc != 2) { +X fprintf(stderr, "usage: setdigital \n"); +X exit(1); +X } +X +X if ((fd = open(argv[1], O_RDWR)) < 0) { +X perror(argv[1]); +X exit(1); +X } +X +X if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) < 0) { +X fprintf(stderr, "error: ioctl read recording mask failed\n"); +X perror("ioctl"); +X close(fd); +X exit(1); +X } +X +X if (!(recmask & SOUND_MASK_DIGITAL1)) { +X fprintf(stderr, "error: cannot find DIGITAL1 device in mixer\n"); +X close(fd); +X exit(1); +X } +X +X if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) < 0) { +X fprintf(stderr, "error: ioctl read recording source failed\n"); +X perror("ioctl"); +X close(fd); +X exit(1); +X } +X +X recsrc |= SOUND_MASK_DIGITAL1; +X +X if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) < 0) { +X fprintf(stderr, "error: ioctl write recording source failed\n"); +X perror("ioctl"); +X close(fd); +X exit(1); +X } +X +X close(fd); +X +X return 0; +} +SHAR_EOF + $shar_touch -am 0828233298 'MultiSound.d/setdigital.c' && + chmod 0664 'MultiSound.d/setdigital.c' || + $echo 'restore of' 'MultiSound.d/setdigital.c' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/setdigital.c:' 'MD5 check failed' +47720746d4367bae9954787c311c56fd MultiSound.d/setdigital.c +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/setdigital.c'`" + test 2111 -eq "$shar_count" || + $echo 'MultiSound.d/setdigital.c:' 'original size' '2111,' 'current size' "$shar_count!" + fi +fi +# ============= MultiSound.d/pinnaclecfg.c ============== +if test -f 'MultiSound.d/pinnaclecfg.c' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/pinnaclecfg.c' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/pinnaclecfg.c' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/pinnaclecfg.c' && +/********************************************************************* +X * +X * pinnaclecfg.c - Pinnacle/Fiji Device Configuration Program +X * +X * This is for NON-PnP mode only. For PnP mode, use isapnptools. +X * +X * This is Linux-specific, and must be run with root permissions. +X * +X * Part of the Turtle Beach MultiSound Sound Card Driver for Linux +X * +X * Copyright (C) 1998 Andrew Veliath +X * +X * This program is free software; you can redistribute it and/or modify +X * it under the terms of the GNU General Public License as published by +X * the Free Software Foundation; either version 2 of the License, or +X * (at your option) any later version. +X * +X * This program is distributed in the hope that it will be useful, +X * but WITHOUT ANY WARRANTY; without even the implied warranty of +X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +X * GNU General Public License for more details. +X * +X * You should have received a copy of the GNU General Public License +X * along with this program; if not, write to the Free Software +X * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +X * +X * $Id: pinnaclecfg.c,v 1.3 1998/08/29 03:32:32 andrewtv Exp $ +X * +X ********************************************************************/ +X +#include +#include +#include +#include +#include +#include +#include +X +#define IREG_LOGDEVICE 0x07 +#define IREG_ACTIVATE 0x30 +#define LD_ACTIVATE 0x01 +#define LD_DISACTIVATE 0x00 +#define IREG_EECONTROL 0x3F +#define IREG_MEMBASEHI 0x40 +#define IREG_MEMBASELO 0x41 +#define IREG_MEMCONTROL 0x42 +#define IREG_MEMRANGEHI 0x43 +#define IREG_MEMRANGELO 0x44 +#define MEMTYPE_8BIT 0x00 +#define MEMTYPE_16BIT 0x02 +#define MEMTYPE_RANGE 0x00 +#define MEMTYPE_HIADDR 0x01 +#define IREG_IO0_BASEHI 0x60 +#define IREG_IO0_BASELO 0x61 +#define IREG_IO1_BASEHI 0x62 +#define IREG_IO1_BASELO 0x63 +#define IREG_IRQ_NUMBER 0x70 +#define IREG_IRQ_TYPE 0x71 +#define IRQTYPE_HIGH 0x02 +#define IRQTYPE_LOW 0x00 +#define IRQTYPE_LEVEL 0x01 +#define IRQTYPE_EDGE 0x00 +X +#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF)) +#define LOBYTE(w) ((BYTE)(w)) +#define MAKEWORD(low,hi) ((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8))) +X +typedef __u8 BYTE; +typedef __u16 USHORT; +typedef __u16 WORD; +X +static int config_port = -1; +X +static int msnd_write_cfg(int cfg, int reg, int value) +{ +X outb(reg, cfg); +X outb(value, cfg + 1); +X if (value != inb(cfg + 1)) { +X fprintf(stderr, "error: msnd_write_cfg: I/O error\n"); +X return -EIO; +X } +X return 0; +} +X +static int msnd_read_cfg(int cfg, int reg) +{ +X outb(reg, cfg); +X return inb(cfg + 1); +} +X +static int msnd_write_cfg_io0(int cfg, int num, WORD io) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io))) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io))) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_io0(int cfg, int num, WORD *io) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X +X *io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO0_BASELO), +X msnd_read_cfg(cfg, IREG_IO0_BASEHI)); +X +X return 0; +} +X +static int msnd_write_cfg_io1(int cfg, int num, WORD io) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io))) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io))) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_io1(int cfg, int num, WORD *io) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X +X *io = MAKEWORD(msnd_read_cfg(cfg, IREG_IO1_BASELO), +X msnd_read_cfg(cfg, IREG_IO1_BASEHI)); +X +X return 0; +} +X +static int msnd_write_cfg_irq(int cfg, int num, WORD irq) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq))) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE)) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_irq(int cfg, int num, WORD *irq) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X +X *irq = msnd_read_cfg(cfg, IREG_IRQ_NUMBER); +X +X return 0; +} +X +static int msnd_write_cfg_mem(int cfg, int num, int mem) +{ +X WORD wmem; +X +X mem >>= 8; +X mem &= 0xfff; +X wmem = (WORD)mem; +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem))) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem))) +X return -EIO; +X if (wmem && msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT))) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_mem(int cfg, int num, int *mem) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X +X *mem = MAKEWORD(msnd_read_cfg(cfg, IREG_MEMBASELO), +X msnd_read_cfg(cfg, IREG_MEMBASEHI)); +X *mem <<= 8; +X +X return 0; +} +X +static int msnd_activate_logical(int cfg, int num) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE)) +X return -EIO; +X return 0; +} +X +static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_write_cfg_io0(cfg, num, io0)) +X return -EIO; +X if (msnd_write_cfg_io1(cfg, num, io1)) +X return -EIO; +X if (msnd_write_cfg_irq(cfg, num, irq)) +X return -EIO; +X if (msnd_write_cfg_mem(cfg, num, mem)) +X return -EIO; +X if (msnd_activate_logical(cfg, num)) +X return -EIO; +X return 0; +} +X +static int msnd_read_cfg_logical(int cfg, int num, WORD *io0, WORD *io1, WORD *irq, int *mem) +{ +X if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) +X return -EIO; +X if (msnd_read_cfg_io0(cfg, num, io0)) +X return -EIO; +X if (msnd_read_cfg_io1(cfg, num, io1)) +X return -EIO; +X if (msnd_read_cfg_irq(cfg, num, irq)) +X return -EIO; +X if (msnd_read_cfg_mem(cfg, num, mem)) +X return -EIO; +X return 0; +} +X +static void usage(void) +{ +X fprintf(stderr, +X "\n" +X "pinnaclecfg 1.0\n" +X "\n" +X "usage: pinnaclecfg [device config]\n" +X "\n" +X "This is for use with the card in NON-PnP mode only.\n" +X "\n" +X "Available devices (not all available for Fiji):\n" +X "\n" +X " Device Description\n" +X " -------------------------------------------------------------------\n" +X " reset Reset all devices (i.e. disable)\n" +X " show Display current device configurations\n" +X "\n" +X " dsp Audio device\n" +X " mpu Internal Kurzweil synth\n" +X " ide On-board IDE controller\n" +X " joystick Joystick port\n" +X "\n"); +X exit(1); +} +X +static int cfg_reset(void) +{ +X int i; +X +X for (i = 0; i < 4; ++i) +X msnd_write_cfg_logical(config_port, i, 0, 0, 0, 0); +X +X return 0; +} +X +static int cfg_show(void) +{ +X int i; +X int count = 0; +X +X for (i = 0; i < 4; ++i) { +X WORD io0, io1, irq; +X int mem; +X msnd_read_cfg_logical(config_port, i, &io0, &io1, &irq, &mem); +X switch (i) { +X case 0: +X if (io0 || irq || mem) { +X printf("dsp 0x%x %d 0x%x\n", io0, irq, mem); +X ++count; +X } +X break; +X case 1: +X if (io0 || irq) { +X printf("mpu 0x%x %d\n", io0, irq); +X ++count; +X } +X break; +X case 2: +X if (io0 || io1 || irq) { +X printf("ide 0x%x 0x%x %d\n", io0, io1, irq); +X ++count; +X } +X break; +X case 3: +X if (io0) { +X printf("joystick 0x%x\n", io0); +X ++count; +X } +X break; +X } +X } +X +X if (count == 0) +X fprintf(stderr, "no devices configured\n"); +X +X return 0; +} +X +static int cfg_dsp(int argc, char *argv[]) +{ +X int io, irq, mem; +X +X if (argc < 3 || +X sscanf(argv[0], "0x%x", &io) != 1 || +X sscanf(argv[1], "%d", &irq) != 1 || +X sscanf(argv[2], "0x%x", &mem) != 1) +X usage(); +X +X if (!(io == 0x290 || +X io == 0x260 || +X io == 0x250 || +X io == 0x240 || +X io == 0x230 || +X io == 0x220 || +X io == 0x210 || +X io == 0x3e0)) { +X fprintf(stderr, "error: io must be one of " +X "210, 220, 230, 240, 250, 260, 290, or 3E0\n"); +X usage(); +X } +X +X if (!(irq == 5 || +X irq == 7 || +X irq == 9 || +X irq == 10 || +X irq == 11 || +X irq == 12)) { +X fprintf(stderr, "error: irq must be one of " +X "5, 7, 9, 10, 11 or 12\n"); +X usage(); +X } +X +X if (!(mem == 0xb0000 || +X mem == 0xc8000 || +X mem == 0xd0000 || +X mem == 0xd8000 || +X mem == 0xe0000 || +X mem == 0xe8000)) { +X fprintf(stderr, "error: mem must be one of " +X "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n"); +X usage(); +X } +X +X return msnd_write_cfg_logical(config_port, 0, io, 0, irq, mem); +} +X +static int cfg_mpu(int argc, char *argv[]) +{ +X int io, irq; +X +X if (argc < 2 || +X sscanf(argv[0], "0x%x", &io) != 1 || +X sscanf(argv[1], "%d", &irq) != 1) +X usage(); +X +X return msnd_write_cfg_logical(config_port, 1, io, 0, irq, 0); +} +X +static int cfg_ide(int argc, char *argv[]) +{ +X int io0, io1, irq; +X +X if (argc < 3 || +X sscanf(argv[0], "0x%x", &io0) != 1 || +X sscanf(argv[0], "0x%x", &io1) != 1 || +X sscanf(argv[1], "%d", &irq) != 1) +X usage(); +X +X return msnd_write_cfg_logical(config_port, 2, io0, io1, irq, 0); +} +X +static int cfg_joystick(int argc, char *argv[]) +{ +X int io; +X +X if (argc < 1 || +X sscanf(argv[0], "0x%x", &io) != 1) +X usage(); +X +X return msnd_write_cfg_logical(config_port, 3, io, 0, 0, 0); +} +X int main(int argc, char *argv[]) { - int fd; - unsigned long recmask, recsrc; - - if (argc != 2) { - fprintf(stderr, "usage: setdigital \n"); - exit(1); - } else - - if ((fd = open(argv[1], O_RDWR)) < 0) { - perror(argv[1]); - exit(1); - } - - if (ioctl(fd, SOUND_MIXER_READ_RECMASK, &recmask) < 0) { - fprintf(stderr, "error: ioctl read recmask failed\n"); - perror("ioctl"); - close(fd); - exit(1); - } - - if (!(recmask & SOUND_MASK_DIGITAL1)) { - fprintf(stderr, "error: cannot find DIGITAL1 device in mixer\n"); - close(fd); - exit(1); - } - - if (ioctl(fd, SOUND_MIXER_READ_RECSRC, &recsrc) < 0) { - fprintf(stderr, "error: ioctl read recsrc failed\n"); - perror("ioctl"); - close(fd); - exit(1); - } - - recsrc |= SOUND_MASK_DIGITAL1; - - if (ioctl(fd, SOUND_MIXER_WRITE_RECSRC, &recsrc) < 0) { - fprintf(stderr, "error: ioctl write recsrc failed\n"); - perror("ioctl"); - close(fd); - exit(1); - } - - close(fd); - - return 0; +X char *device; +X int rv = 0; +X +X --argc; ++argv; +X +X if (argc < 2) +X usage(); +X +X sscanf(argv[0], "0x%x", &config_port); +X if (config_port != 0x250 && config_port != 0x260 && config_port != 0x270) { +X fprintf(stderr, "error: must be 0x250, 0x260 or 0x270\n"); +X exit(1); +X } +X if (ioperm(config_port, 2, 1)) { +X perror("ioperm"); +X fprintf(stderr, "note: pinnaclecfg must be run as root\n"); +X exit(1); +X } +X device = argv[1]; +X +X argc -= 2; argv += 2; +X +X if (strcmp(device, "reset") == 0) +X rv = cfg_reset(); +X else if (strcmp(device, "show") == 0) +X rv = cfg_show(); +X else if (strcmp(device, "dsp") == 0) +X rv = cfg_dsp(argc, argv); +X else if (strcmp(device, "mpu") == 0) +X rv = cfg_mpu(argc, argv); +X else if (strcmp(device, "ide") == 0) +X rv = cfg_ide(argc, argv); +X else if (strcmp(device, "joystick") == 0) +X rv = cfg_joystick(argc, argv); +X else { +X fprintf(stderr, "error: unknown device %s\n", device); +X usage(); +X } +X +X if (rv) +X fprintf(stderr, "error: device configuration failed\n"); +X +X return 0; } --- end setdigital.c -- +SHAR_EOF + $shar_touch -am 0905082598 'MultiSound.d/pinnaclecfg.c' && + chmod 0664 'MultiSound.d/pinnaclecfg.c' || + $echo 'restore of' 'MultiSound.d/pinnaclecfg.c' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/pinnaclecfg.c:' 'MD5 check failed' +71f99b834a2845daae8ae034623e313e MultiSound.d/pinnaclecfg.c +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/pinnaclecfg.c'`" + test 10301 -eq "$shar_count" || + $echo 'MultiSound.d/pinnaclecfg.c:' 'original size' '10301,' 'current size' "$shar_count!" + fi +fi +# ============= MultiSound.d/Makefile ============== +if test -f 'MultiSound.d/Makefile' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/Makefile' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/Makefile' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/Makefile' && +CC = gcc +CFLAGS = -O +PROGS = setdigital pinnaclecfg conv +X +all: $(PROGS) +X +clean: +X rm -f $(PROGS) +SHAR_EOF + $shar_touch -am 0828231798 'MultiSound.d/Makefile' && + chmod 0664 'MultiSound.d/Makefile' || + $echo 'restore of' 'MultiSound.d/Makefile' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/Makefile:' 'MD5 check failed' +ab95a049d10611a5e5d559a56965b33f MultiSound.d/Makefile +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/Makefile'`" + test 96 -eq "$shar_count" || + $echo 'MultiSound.d/Makefile:' 'original size' '96,' 'current size' "$shar_count!" + fi +fi +# ============= MultiSound.d/conv.l ============== +if test -f 'MultiSound.d/conv.l' && test "$first_param" != -c; then + $echo 'x -' SKIPPING 'MultiSound.d/conv.l' '(file already exists)' +else + $echo 'x -' extracting 'MultiSound.d/conv.l' '(text)' + sed 's/^X//' << 'SHAR_EOF' > 'MultiSound.d/conv.l' && +%% +[ \n\t,\r] +\;.* +DB +[0-9A-Fa-f]+H { int n; sscanf(yytext, "%xH", &n); printf("%c", n); } +%% +int yywrap() { return 1; } +main() { yylex(); } +SHAR_EOF + $shar_touch -am 0828231798 'MultiSound.d/conv.l' && + chmod 0664 'MultiSound.d/conv.l' || + $echo 'restore of' 'MultiSound.d/conv.l' 'failed' + if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \ + && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then + md5sum -c << SHAR_EOF >/dev/null 2>&1 \ + || $echo 'MultiSound.d/conv.l:' 'MD5 check failed' +d2411fc32cd71a00dcdc1f009e858dd2 MultiSound.d/conv.l +SHAR_EOF + else + shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'MultiSound.d/conv.l'`" + test 141 -eq "$shar_count" || + $echo 'MultiSound.d/conv.l:' 'original size' '141,' 'current size' "$shar_count!" + fi +fi +rm -fr _sh21233 +exit 0 diff -u --recursive --new-file v2.1.125/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.125/linux/MAINTAINERS Fri Oct 9 13:27:04 1998 +++ linux/MAINTAINERS Sat Oct 10 09:56:11 1998 @@ -16,7 +16,8 @@ SMC etherpower for that.) 3. Make sure your changes compile correctly in multiple - configurations. + configurations. In paticular check changes work both as a module + and built into the kernel. 4. When you are happy with a change make it generally available for testing and await feedback. @@ -28,7 +29,8 @@ job the maintainers (and especially Linus) do is to keep things looking the same. Sometimes this means that the clever hack in your driver to get around a problem actual needs to become a - generalized kernel feature ready for next time. + generalized kernel feature ready for next time. See + Documentation/CodingStyle for guidance here. PLEASE try to include any credit lines you want added with the patch. It avoids people being missed off by mistake and makes @@ -240,6 +242,11 @@ L: linux-net@vger.rutgers.edu S: Maintained +ETHERTEAM 16I DRIVER +P: Mika Kuoppala +M: miku@iki.fi +S: Maintained + EXT2 FILE SYSTEM P: Remy Card M: Remy.Card@linux.org @@ -303,6 +310,12 @@ L: linux-hams@vger.rutgers.edu S: Maintained +HIPPI +P: Jes Sorensen +M: Jes.Sorensen@cern.ch +L: linux-hippi@sunsite.auc.dk +S: Maintained + HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series P: Jaroslav Kysela M: perex@jcu.cz @@ -702,6 +715,12 @@ L: linux-x25@vger.rutgers.edu S: Maintained +Z85230 SYNCHRONOUS DRIVER +P: Alan Cox +M: alan@redhat.com +W: http://roadrunner.swansea.linux.org.uk/synchronous.shtml +S: Maintained + Z8530 DRIVER FOR AX.25 P: Joerg Reuter M: jreuter@poboxes.com @@ -709,7 +728,6 @@ W: http://qsl.net/dl1bke/ L: linux-hams@vger.rutgers.edu S: Maintained - REST: P: Linus Torvalds diff -u --recursive --new-file v2.1.125/linux/Makefile linux/Makefile --- v2.1.125/linux/Makefile Fri Oct 9 13:27:04 1998 +++ linux/Makefile Fri Oct 16 20:33:22 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 125 +SUBLEVEL = 126 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.1.125/linux/README linux/README --- v2.1.125/linux/README Tue Aug 18 22:02:01 1998 +++ linux/README Sat Oct 10 10:30:35 1998 @@ -96,15 +96,6 @@ the current directory, but an alternative directory can be specified as the second argument. - - Make sure your /usr/include/asm, /usr/include/linux, and /usr/include/scsi - directories are just symlinks to the kernel sources: - - cd /usr/include - rm -rf asm linux scsi - ln -s /usr/src/linux/include/asm-i386 asm - ln -s /usr/src/linux/include/linux linux - ln -s /usr/src/linux/include/scsi scsi - - Make sure you have no stale .o files and dependencies lying around: cd /usr/src/linux diff -u --recursive --new-file v2.1.125/linux/arch/alpha/Makefile linux/arch/alpha/Makefile --- v2.1.125/linux/arch/alpha/Makefile Wed Sep 9 14:51:03 1998 +++ linux/arch/alpha/Makefile Mon Oct 12 11:40:12 1998 @@ -19,17 +19,23 @@ # Determine if GCC understands the -mcpu= option. have_mcpu := $(shell if $(CC) -mcpu=ev5 -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo y; else echo n; fi) -# If GENERIC, make sure to turn off any instruction set extensions that -# the host compiler might have on by default. Given that EV4 and EV5 -# have the same instruction set, prefer EV5 because an EV5 schedule is -# more likely to keep an EV4 processor busy than vice-versa. -ifeq ($(CONFIG_ALPHA_GENERIC)$(have_mcpu),yy) - CFLAGS := $(CFLAGS) -mcpu=ev5 -endif - -# If EV6, turn on the proper optimizations. -ifeq ($(CONFIG_ALPHA_EV6)$(have_mcpu),yy) - CFLAGS := $(CFLAGS) -mcpu=ev6 +# Turn on the proper cpu optimizations. +ifeq ($(have_mcpu),y) + # If GENERIC, make sure to turn off any instruction set extensions that + # the host compiler might have on by default. Given that EV4 and EV5 + # have the same instruction set, prefer EV5 because an EV5 schedule is + # more likely to keep an EV4 processor busy than vice-versa. + ifeq ($(CONFIG_ALPHA_GENERIC),y) + CFLAGS := $(CFLAGS) -mcpu=ev5 + endif + ifeq ($(CONFIG_ALPHA_EV4),y) + CFLAGS := $(CFLAGS) -mcpu=ev4 + endif + # Leave out EV5, since it is too hard to figure out whether we + # should use EV56 insns or not. + ifeq ($(CONFIG_ALPHA_EV6),y) + CFLAGS := $(CFLAGS) -mcpu=ev6 + endif endif # For TSUNAMI, we must have the assembler not emulate our instructions. diff -u --recursive --new-file v2.1.125/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile --- v2.1.125/linux/arch/alpha/boot/Makefile Wed Sep 9 14:51:03 1998 +++ linux/arch/alpha/boot/Makefile Mon Oct 12 11:40:12 1998 @@ -36,7 +36,10 @@ tools/mkbb bootimage tools/lxboot bootpfile: tools/bootph vmlinux.nh - ( cat tools/bootph vmlinux.nh ) > bootpfile + cat tools/bootph vmlinux.nh > bootpfile +ifdef INITRD + cat $(INITRD) >> bootpfile +endif srmboot: bootdevice bootimage dd if=bootimage of=$(BOOTDEV) bs=512 seek=1 skip=1 @@ -48,15 +51,18 @@ vmlinux.gz: vmlinux gzip -fv9 vmlinux -# -# A raw binary without header. Used by raw boot. -# main.o: ksize.h bootp.o: ksize.h -ksize.h: $(OBJSTRIP) vmlinux.nh - echo "#define KERNEL_SIZE `$(OBJSTRIP) -p vmlinux.nh /dev/null`" > $@ +ksize.h: vmlinux.nh dummy + echo "#define KERNEL_SIZE `ls -l vmlinux.nh | awk '{print $$5}'`" > $@T +ifdef INITRD + [ -f $(INITRD) ] || exit 1 + echo "#define INITRD_SIZE `ls -l $(INITRD) | awk '{print $$5}'`" >> $@T +endif + cmp -s $@T $@ || mv -f $@T $@ + rm -f $@T vmlinux.nh: $(VMLINUX) $(OBJSTRIP) $(OBJSTRIP) -v $(VMLINUX) vmlinux.nh @@ -91,3 +97,5 @@ rm -f vmlinux.nh ksize.h dep: + +dummy: diff -u --recursive --new-file v2.1.125/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c --- v2.1.125/linux/arch/alpha/boot/bootp.c Wed Sep 9 14:51:03 1998 +++ linux/arch/alpha/boot/bootp.c Mon Oct 12 11:40:12 1998 @@ -22,74 +22,30 @@ #include "ksize.h" -extern int vsprintf(char *, const char *, va_list); extern unsigned long switch_to_osf_pal(unsigned long nr, struct pcb_struct * pcb_va, struct pcb_struct * pcb_pa, - unsigned long vptb, unsigned long *kstk); + unsigned long *vptb); -extern long dispatch(long code, ...); - -static void -puts(const char *str, int len) -{ - long written; - - while (len > 0) { - written = dispatch(CCB_PUTS, 0, str, len); - if (written < 0) - break; - len -= (unsigned int) written; - str += (unsigned int) written; - } -} - -int printk(const char * fmt, ...) -{ - va_list args; - int i, j, remaining, num_nl; - static char buf[1024]; - - va_start(args, fmt); - i = vsprintf(buf, fmt, args); - va_end(args); - - /* expand \n into \r\n: */ - - num_nl = 0; - for (j = 0; j < i; ++j) { - if (buf[j] == '\n') - ++num_nl; - } - remaining = i + num_nl; - for (j = i - 1; j >= 0; --j) { - buf[j + num_nl] = buf[j]; - if (buf[j] == '\n') { - --num_nl; - buf[j + num_nl] = '\r'; - } - } - - puts(buf, remaining); - return i; -} - -#define hwrpb (*INIT_HWRPB) +struct hwrpb_struct *hwrpb = INIT_HWRPB; +static struct pcb_struct pcb_va[1]; /* * Find a physical address of a virtual object.. * * This is easy using the virtual page table address. */ -struct pcb_struct * find_pa(unsigned long *vptb, struct pcb_struct * pcb) + +static inline void * +find_pa(unsigned long *vptb, void *ptr) { - unsigned long address = (unsigned long) pcb; + unsigned long address = (unsigned long) ptr; unsigned long result; result = vptb[address >> 13]; result >>= 32; result <<= 13; result |= address & 0x1fff; - return (struct pcb_struct *) result; + return (void *) result; } /* @@ -101,31 +57,19 @@ * code has the L1 page table identity-map itself in the second PTE * in the L1 page table. Thus the L1-page is virtually addressable * itself (through three levels) at virtual address 0x200802000. - * - * As we don't want it there anyway, we also move the L1 self-map - * up as high as we can, so that the last entry in the L1 page table - * maps the page tables. - * - * As a result, the OSF/1 pal-code will instead use a virtual page table - * map located at 0xffffffe00000000. */ -#define pcb_va ((struct pcb_struct *) 0x20000000) -#define old_vptb (0x0000000200000000UL) -#define new_vptb (0xfffffffe00000000UL) -void pal_init(void) + +#define VPTB ((unsigned long *) 0x200000000) +#define L1 ((unsigned long *) 0x200802000) + +void +pal_init(void) { - unsigned long i, rev, sum; - unsigned long *L1, *l; + unsigned long i, rev; struct percpu_struct * percpu; struct pcb_struct * pcb_pa; - /* Find the level 1 page table and duplicate it in high memory */ - L1 = (unsigned long *) 0x200802000UL; /* (1<<33 | 1<<23 | 1<<13) */ - L1[1023] = L1[1]; - - percpu = (struct percpu_struct *) - (hwrpb.processor_offset + (unsigned long) &hwrpb), - + /* Create the dummy PCB. */ pcb_va->ksp = 0; pcb_va->usp = 0; pcb_va->ptbr = L1[1] >> 32; @@ -133,58 +77,45 @@ pcb_va->pcc = 0; pcb_va->unique = 0; pcb_va->flags = 1; - pcb_pa = find_pa((unsigned long *) old_vptb, pcb_va); - printk("Switching to OSF PAL-code .. "); + pcb_va->res1 = 0; + pcb_va->res2 = 0; + pcb_pa = find_pa(VPTB, pcb_va); + /* * a0 = 2 (OSF) * a1 = return address, but we give the asm the vaddr of the PCB * a2 = physical addr of PCB * a3 = new virtual page table pointer - * a4 = KSP (but we give it 0, asm sets it) + * a4 = KSP (but the asm sets it) */ - i = switch_to_osf_pal( - 2, - pcb_va, - pcb_pa, - new_vptb, - 0); + srm_printk("Switching to OSF PAL-code .. "); + + i = switch_to_osf_pal(2, pcb_va, pcb_pa, VPTB); if (i) { - printk("failed, code %ld\n", i); + srm_printk("failed, code %ld\n", i); halt(); } - rev = percpu->pal_revision = percpu->palcode_avail[2]; - hwrpb.vptb = new_vptb; + percpu = (struct percpu_struct *) + (INIT_HWRPB->processor_offset + (unsigned long) INIT_HWRPB); + rev = percpu->pal_revision = percpu->palcode_avail[2]; - /* update checksum: */ - sum = 0; - for (l = (unsigned long *) &hwrpb; - l < (unsigned long *) &hwrpb.chksum; - ++l) - sum += *l; - hwrpb.chksum = sum; - - printk("Ok (rev %lx)\n", rev); - /* remove the old virtual page-table mapping */ - L1[1] = 0; + srm_printk("Ok (rev %lx)\n", rev); tbia(); /* do it directly in case we are SMP */ } -static inline long load(unsigned long dst, - unsigned long src, - unsigned long count) +static inline void +load(unsigned long dst, unsigned long src, unsigned long count) { - extern void * memcpy(void *, const void *, size_t); - memcpy((void *)dst, (void *)src, count); - return count; } /* * Start the kernel. */ -static void runkernel(void) +static inline void +runkernel(void) { __asm__ __volatile__( "bis %1,%1,$30\n\t" @@ -199,65 +130,82 @@ #define KERNEL_ORIGIN \ ((((unsigned long)&_end) + 511) & ~511) -void start_kernel(void) +void +start_kernel(void) { - static long i; - static int nbytes; /* - * note that this crufty stuff with static and envval and envbuf - * is because: + * Note that this crufty stuff with static and envval + * and envbuf is because: * - * 1. frequently, the stack is is short, and we don't want to overrun; - * 2. frequently the stack is where we are going to copy the kernel to; - * 3. a certain SRM console required the GET_ENV output to stack. + * 1. Frequently, the stack is short, and we don't want to overrun; + * 2. Frequently the stack is where we are going to copy the kernel to; + * 3. A certain SRM console required the GET_ENV output to stack. + * ??? A comment in the aboot sources indicates that the GET_ENV + * destination must be quadword aligned. Might this explain the + * behaviour, rather than requiring output to the stack, which + * seems rather far-fetched. */ - static char envval[256]; - char envbuf[256]; + static long nbytes; + static char envval[256] __attribute__((aligned(8))); +#ifdef INITRD_SIZE + static unsigned long initrd_start; +#endif - printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n"); - if (hwrpb.pagesize != 8192) { - printk("Expected 8kB pages, got %ldkB\n", - hwrpb.pagesize >> 10); + srm_printk("Linux/AXP bootp loader for Linux " UTS_RELEASE "\n"); + if (INIT_HWRPB->pagesize != 8192) { + srm_printk("Expected 8kB pages, got %ldkB\n", + INIT_HWRPB->pagesize >> 10); + return; + } + if (INIT_HWRPB->vptb != (unsigned long) VPTB) { + srm_printk("Expected vptb at %p, got %p\n", + VPTB, (void *)INIT_HWRPB->vptb); return; } pal_init(); - nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, - envbuf, sizeof(envbuf)); - if (nbytes < 0 || nbytes >= sizeof(envbuf)) { +#ifdef INITRD_SIZE + /* The initrd must be page-aligned. See below for the + cause of the magic number 5. */ + initrd_start = ((START_ADDR + 5*KERNEL_SIZE) | (PAGE_SIZE-1)) + 1; + srm_printk("Initrd positioned at %#lx\n", initrd_start); +#endif + + nbytes = srm_dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS, + envval, sizeof(envval)); + if (nbytes < 0 || nbytes >= sizeof(envval)) { nbytes = 0; } - envbuf[nbytes] = '\0'; - memcpy(envval, envbuf, nbytes+1); - printk("Loading the kernel...'%s'\n", envval); + envval[nbytes] = '\0'; + srm_printk("Loading the kernel...'%s'\n", envval); /* NOTE: *no* callbacks or printouts from here on out!!! */ -#if 1 /* - * this is a hack, as some consoles seem to get virtual 20000000 + * This is a hack, as some consoles seem to get virtual 20000000 * (ie where the SRM console puts the kernel bootp image) memory * overlapping physical 310000 memory, which causes real problems * when attempting to copy the former to the latter... :-( * - * so, we first move the kernel virtual-to-physical way above where + * So, we first move the kernel virtual-to-physical way above where * we physically want the kernel to end up, then copy it from there * to its final resting place... ;-} * - * sigh... + * Sigh... */ - i = load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE); - i = load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE); -#else - i = load(START_ADDR, KERNEL_ORIGIN, KERNEL_SIZE); +#ifdef INITRD_SIZE + load(initrd_start, KERNEL_ORIGIN+KERNEL_SIZE, INITRD_SIZE); #endif + load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE); + load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE); + memset((char*)ZERO_PAGE, 0, PAGE_SIZE); strcpy((char*)ZERO_PAGE, envval); +#ifdef INITRD_SIZE + ((long *)(ZERO_PAGE+256))[0] = initrd_start; + ((long *)(ZERO_PAGE+256))[1] = INITRD_SIZE; +#endif runkernel(); - - for (i = 0 ; i < 0x100000000 ; i++) - /* nothing */; - halt(); } diff -u --recursive --new-file v2.1.125/linux/arch/alpha/boot/head.S linux/arch/alpha/boot/head.S --- v2.1.125/linux/arch/alpha/boot/head.S Sat Mar 16 03:52:12 1996 +++ linux/arch/alpha/boot/head.S Mon Oct 12 11:40:12 1998 @@ -6,28 +6,22 @@ #include -#define halt .long PAL_halt - .set noreorder .globl __start .ent __start __start: - bis $31,$31,$31 - br 1f - /* room for the initial PCB, which comes here */ - .quad 0,0,0,0,0,0,0,0 -1: br $27,2f -2: ldgp $29,0($27) - lda $27,start_kernel - jsr $26,($27),start_kernel - halt + br $29,2f +2: ldgp $29,0($29) + jsr $26,start_kernel + call_pal PAL_halt .end __start .align 5 .globl wrent .ent wrent wrent: - .long PAL_wrent + .prologue 0 + call_pal PAL_wrent ret ($26) .end wrent @@ -35,7 +29,8 @@ .globl wrkgp .ent wrkgp wrkgp: - .long PAL_wrkgp + .prologue 0 + call_pal PAL_wrkgp ret ($26) .end wrkgp @@ -44,6 +39,7 @@ .ent switch_to_osf_pal switch_to_osf_pal: subq $30,128,$30 + .frame $30,128,$26 stq $26,0($30) stq $1,8($30) stq $2,16($30) @@ -60,11 +56,12 @@ stq $13,104($30) stq $14,112($30) stq $15,120($30) + .prologue 0 stq $30,0($17) /* save KSP in PCB */ bis $30,$30,$20 /* a4 = KSP */ - br $17,__do_swppal + br $17,1f ldq $26,0($30) ldq $1,8($30) @@ -84,56 +81,22 @@ ldq $15,120($30) addq $30,128,$30 ret ($26) - -__do_swppal: - .long PAL_swppal +1: call_pal PAL_swppal .end switch_to_osf_pal -.globl dispatch -.ent dispatch -dispatch: - subq $30,80,$30 - stq $26,0($30) - stq $29,8($30) - - stq $8,16($30) - stq $9,24($30) - stq $10,32($30) - stq $11,40($30) - stq $12,48($30) - stq $13,56($30) - stq $14,64($30) - stq $15,72($30) - - lda $1,0x10000000 /* hwrpb */ - ldq $2,0xc0($1) /* crb offset */ - addq $2,$1,$2 /* crb */ - ldq $27,0($2) /* dispatch procedure value */ - - ldq $2,8($27) /* dispatch call address */ - jsr $26,($2) /* call it (weird VMS call seq) */ - - ldq $26,0($30) - ldq $29,8($30) - - ldq $8,16($30) - ldq $9,24($30) - ldq $10,32($30) - ldq $11,40($30) - ldq $12,48($30) - ldq $13,56($30) - ldq $14,64($30) - ldq $15,72($30) - - addq $30,80,$30 - ret $31,($26) -.end dispatch - .align 3 .globl tbi .ent tbi tbi: - .long PAL_tbi + .prologue 0 + call_pal PAL_tbi ret ($26) .end tbi + .align 3 + .globl halt + .ent halt +halt: + .prologue 0 + call_pal PAL_halt + .end halt diff -u --recursive --new-file v2.1.125/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.1.125/linux/arch/alpha/config.in Tue Aug 18 22:02:01 1998 +++ linux/arch/alpha/config.in Mon Oct 12 11:40:12 1998 @@ -175,8 +175,6 @@ define_bool CONFIG_ALPHA_AVANTI y fi -#bool 'Echo console messages on /dev/ttyS0 (COM1)' CONFIG_SERIAL_ECHO - if [ "$CONFIG_PCI" = "y" ]; then bool 'PCI quirks' CONFIG_PCI_QUIRKS if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.1.125/linux/arch/alpha/kernel/alpha_ksyms.c Tue Aug 18 22:02:01 1998 +++ linux/arch/alpha/kernel/alpha_ksyms.c Mon Oct 12 11:40:12 1998 @@ -136,6 +136,37 @@ EXPORT_SYMBOL(__strncpy_from_user); EXPORT_SYMBOL(__strlen_user); +/* + * SMP-specific symbols. + */ + +#ifdef __SMP__ +EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(flush_tlb_all); +EXPORT_SYMBOL(flush_tlb_mm); +EXPORT_SYMBOL(flush_tlb_page); +EXPORT_SYMBOL(flush_tlb_range); +EXPORT_SYMBOL(cpu_data); +EXPORT_SYMBOL(cpu_number_map); +EXPORT_SYMBOL(global_bh_lock); +EXPORT_SYMBOL(global_bh_count); +EXPORT_SYMBOL(synchronize_bh); +EXPORT_SYMBOL(global_irq_holder); +EXPORT_SYMBOL(__global_cli); +EXPORT_SYMBOL(__global_sti); +EXPORT_SYMBOL(__global_save_flags); +EXPORT_SYMBOL(__global_restore_flags); +#if DEBUG_SPINLOCK +EXPORT_SYMBOL(spin_unlock); +EXPORT_SYMBOL(spin_lock); +EXPORT_SYMBOL(spin_trylock); +#endif +#if DEBUG_RWLOCK +EXPORT_SYMBOL(write_lock); +EXPORT_SYMBOL(read_lock); +#endif +#endif /* __SMP__ */ + /* * The following are special because they're not called * explicitly (the C compiler or assembler generates them in diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v2.1.125/linux/arch/alpha/kernel/bios32.c Wed Sep 9 14:51:03 1998 +++ linux/arch/alpha/kernel/bios32.c Mon Oct 12 11:40:12 1998 @@ -524,16 +524,8 @@ 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)); - idx++; /* skip extra 4 bytes */ - continue; + break; case PCI_BASE_ADDRESS_MEM_TYPE_1M: /* @@ -594,6 +586,29 @@ off, base); handle = PCI_HANDLE(bus->number) | base; dev->base_address[idx] = handle; + + /* + * Currently for 64-bit cards, we simply do the usual + * for setup of the first register (low) of the pair, + * and then clear out the second (high) register, as + * we are not yet able to do 64-bit addresses, and + * setting the high register to 0 allows 32-bit SAC + * addresses to be used. + */ + if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) { + pcibios_write_config_dword(bus->number, + dev->devfn, + off+4, 0); + /* Bypass hi reg in the loop. */ + dev->base_address[++idx] = 0; + + printk("bios32 WARNING: " + "handling 64-bit device in " + "slot %d, function %d: \n", + PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + } + DBG_DEVS(("layout_dev: dev 0x%x MEM @ 0x%lx (0x%x)\n", dev->device, handle, size)); } @@ -692,36 +707,46 @@ struct pci_dev *bridge = bus->self; DBG_DEVS(("layout_bus: config bus %d bridge\n", bus->number)); + /* * Set up the top and bottom of the PCI I/O segment * for this bus. */ pcibios_read_config_dword(bridge->bus->number, bridge->devfn, - 0x1c, &l); + PCI_IO_BASE, &l); l &= 0xffff0000; l |= ((bio >> 8) & 0x00f0) | ((tio - 1) & 0xf000); pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - 0x1c, l); + PCI_IO_BASE, l); + + /* Also clear out the upper 16 bits. */ + pcibios_write_config_dword(bridge->bus->number, bridge->devfn, + PCI_IO_BASE_UPPER16, 0); + /* * Set up the top and bottom of the PCI Memory segment * for this bus. */ l = ((bmem & 0xfff00000) >> 16) | ((tmem - 1) & 0xfff00000); pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - 0x20, l); + PCI_MEMORY_BASE, l); /* * Turn off downstream PF memory address range: */ pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - 0x24, 0x0000ffff); + PCI_PREF_MEMORY_BASE, 0x0000ffff); + /* * Tell bridge that there is an ISA bus in the system, * and (possibly) a VGA as well. */ + /* ??? This appears to be a single-byte write into MIN_GNT. + What is up with this? */ l = 0x00040000; /* ISA present */ if (found_vga) l |= 0x00080000; /* VGA present */ pcibios_write_config_dword(bridge->bus->number, bridge->devfn, 0x3c, l); + /* * Clear status bits, enable I/O (for downstream I/O), * turn on master enable (for upstream I/O), turn on @@ -729,7 +754,7 @@ * master enable (for upstream memory and I/O). */ pcibios_write_config_dword(bridge->bus->number, bridge->devfn, - 0x4, 0xffff0007); + PCI_COMMAND, 0xffff0007); } DBG_DEVS(("layout_bus: bus %d finished\n", bus->number)); return found_vga; diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c --- v2.1.125/linux/arch/alpha/kernel/core_pyxis.c Wed Sep 9 14:51:03 1998 +++ linux/arch/alpha/kernel/core_pyxis.c Mon Oct 12 11:40:12 1998 @@ -99,33 +99,13 @@ mk_conf_addr(u8 bus, u8 device_fn, u8 where, unsigned long *pci_addr, unsigned char *type1) { - unsigned long addr; + *type1 = (bus == 0) ? 0 : 1; + *pci_addr = (bus << 16) | (device_fn << 8) | (where); DBG_CNF(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," - " pci_addr=0x%p, type1=0x%p)\n", - bus, device_fn, where, pci_addr, type1)); + " returning address 0x%p\n" + bus, device_fn, where, *pci_addr)); - if (bus == 0) { - int device; - - device = device_fn >> 3; - /* Type 0 configuration cycle. */ -#if NOT_NOW - if (device > 20) { - DBG_CNF(("mk_conf_addr: device (%d) > 20, return -1\n", - device)); - return -1; - } -#endif - *type1 = 0; - addr = (device_fn << 8) | (where); - } else { - /* Type 1 configuration cycle. */ - *type1 = 1; - addr = (bus << 16) | (device_fn << 8) | (where); - } - *pci_addr = addr; - DBG_CNF(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); return 0; } @@ -142,12 +122,11 @@ stat0 = *(vuip)PYXIS_ERR; *(vuip)PYXIS_ERR = stat0; mb(); temp = *(vuip)PYXIS_ERR; /* re-read to force write */ - DBG_CNF(("conf_read: PYXIS ERR was 0x%x\n", stat0)); /* If Type1 access, must set PYXIS CFG. */ if (type1) { pyxis_cfg = *(vuip)PYXIS_CFG; - *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb(); + *(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb(); temp = *(vuip)PYXIS_CFG; /* re-read to force write */ } @@ -172,14 +151,15 @@ /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ if (type1) { - *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb(); + *(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb(); temp = *(vuip)PYXIS_CFG; /* re-read to force write */ } + __restore_flags(flags); + DBG_CNF(("conf_read(addr=0x%lx, type1=%d) = %#x\n", addr, type1, value)); - __restore_flags(flags); return value; } @@ -190,9 +170,6 @@ unsigned int stat0, temp; unsigned int pyxis_cfg = 0; - DBG_CNF(("conf_write(addr=%#lx, value=%#x, type1=%d)\n", - addr, value, type1)); - __save_and_cli(flags); /* avoid getting hit by machine check */ /* Reset status register to avoid losing errors. */ @@ -203,7 +180,7 @@ /* If Type1 access, must set PYXIS CFG. */ if (type1) { pyxis_cfg = *(vuip)PYXIS_CFG; - *(vuip)PYXIS_CFG = pyxis_cfg | 1; mb(); + *(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb(); temp = *(vuip)PYXIS_CFG; /* re-read to force write */ } @@ -216,18 +193,20 @@ /* Access configuration space. */ *(vuip)addr = value; mb(); - mb(); /* magic */ - temp = *(vuip)PYXIS_ERR; /* do a PYXIS read to force the write */ + temp = *(vuip)addr; /* read back to force the write */ PYXIS_mcheck_expected = 0; mb(); /* If Type1 access, must reset IOC CFG so normal IO space ops work. */ if (type1) { - *(vuip)PYXIS_CFG = pyxis_cfg & ~1; mb(); + *(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb(); temp = *(vuip)PYXIS_CFG; /* re-read to force write */ } __restore_flags(flags); + + DBG_CNF(("conf_write(addr=%#lx, value=%#x, type1=%d)\n", + addr, value, type1)); } int diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.125/linux/arch/alpha/kernel/entry.S Wed Sep 9 14:51:03 1998 +++ linux/arch/alpha/kernel/entry.S Mon Oct 12 11:40:12 1998 @@ -552,7 +552,6 @@ ret_from_sys_call: cmovne $26,0,$19 /* $19 = 0 => non-restartable */ /* check bottom half interrupts */ - bne $1,ret_from_handle_bh ldq $3,bh_active ldq $4,bh_mask and $3,$4,$2 @@ -678,7 +677,7 @@ bis $30,$30,$18 bis $31,$31,$16 jsr $26,do_signal - lda $30,SWITCH_STACK_SIZE($30) + bsr $1,undo_switch_stack br $31,restore_all .end entSys diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.1.125/linux/arch/alpha/kernel/head.S Tue Aug 18 22:02:02 1998 +++ linux/arch/alpha/kernel/head.S Mon Oct 12 11:40:12 1998 @@ -9,8 +9,6 @@ #include -#define halt call_pal PAL_halt - .globl swapper_pg_dir .globl _stext swapper_pg_dir=SWAPPER_PGD @@ -29,28 +27,28 @@ lda $30,0x4000($8) /* ... and then we can start the kernel. */ jsr $26,start_kernel - halt + call_pal PAL_halt .end __start #ifdef __SMP__ .align 3 .globl __start_cpu .ent __start_cpu - /* on entry here from SRM console, the HWPCB of this processor */ - /* has been loaded, and $27 contains the task pointer */ + /* On entry here from SRM console, the HWPCB of this processor + has been loaded, and $27 contains the task pointer */ __start_cpu: .prologue 0 - /* first order of business, load the GP */ + /* First order of business, load the GP */ br $26,1f 1: ldgp $29,0($26) /* We need to get current loaded up with our first task... */ - lda $8,0($27) - /* set FEN */ + mov $27,$8 + /* Set FEN */ lda $16,1($31) call_pal PAL_wrfen /* ... and then we can start the processor. */ jsr $26,start_secondary - halt + call_pal PAL_halt .end __start_cpu #endif /* __SMP__ */ @@ -121,10 +119,20 @@ .globl wripir .ent wripir wripir: + .prologue 0 call_pal PAL_wripir ret ($26) .end wripir + .align 3 + .globl wrvptptr + .ent wrvptptr +wrvptptr: + .prologue 0 + call_pal PAL_wrvptptr + ret ($26) + .end wrvptptr + # # The following two functions are needed for supporting SRM PALcode # on the PC164 (at least), since that PALcode manages the interrupt @@ -152,3 +160,17 @@ call_pal PAL_cserve ret ($26) .end cserve_dis + + # + # It is handy, on occasion, to make halt actually just loop. + # Putting it here means we dont have to recompile the whole + # kernel. + # + + .align 3 + .globl halt + .ent halt +halt: + .prologue 0 + call_pal PAL_halt + .end halt diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.1.125/linux/arch/alpha/kernel/irq.c Wed Sep 9 14:51:03 1998 +++ linux/arch/alpha/kernel/irq.c Mon Oct 12 11:40:12 1998 @@ -311,26 +311,41 @@ int get_irq_list(char *buf) { - int i, len = 0; + int i, j; struct irqaction * action; - int cpu = smp_processor_id(); + char *p = buf; + +#ifdef __SMP__ + p += sprintf(p, " "); + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "CPU%d ", j); + *p++ = '\n'; +#endif for (i = 0; i < NR_IRQS; i++) { action = irq_action[i]; if (!action) continue; - len += sprintf(buf+len, "%2d: %10u %c %s", - i, kstat.irqs[cpu][i], - (action->flags & SA_INTERRUPT) ? '+' : ' ', - action->name); + p += sprintf(p, "%3d: ",i); +#ifndef __SMP__ + p += sprintf(p, "%10u ", kstat_irqs(i)); +#else + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + kstat.irqs[cpu_logical_map(j)][i]); +#endif + p += sprintf(p, " %c%s", + (action->flags & SA_INTERRUPT)?'+':' ', + action->name); + for (action=action->next; action; action = action->next) { - len += sprintf(buf+len, ", %s%s", - (action->flags & SA_INTERRUPT) ? "+":"", - action->name); + p += sprintf(p, ", %c%s", + (action->flags & SA_INTERRUPT)?'+':' ', + action->name); } - len += sprintf(buf+len, "\n"); + *p++ = '\n'; } - return len; + return p - buf; } #ifdef __SMP__ @@ -427,8 +442,10 @@ /* * Finally. */ +#if DEBUG_SPINLOCK global_irq_lock.task = current; global_irq_lock.previous = where; +#endif global_irq_holder = cpu; previous_irqholder = where; } diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/irq.h linux/arch/alpha/kernel/irq.h --- v2.1.125/linux/arch/alpha/kernel/irq.h Wed Sep 9 14:51:03 1998 +++ linux/arch/alpha/kernel/irq.h Mon Oct 12 11:40:12 1998 @@ -11,12 +11,8 @@ #define STANDARD_INIT_IRQ_PROLOG \ outb(0, DMA1_RESET_REG); \ outb(0, DMA2_RESET_REG); \ - outb(0, DMA1_MASK_REG); \ - outb(0, DMA2_MASK_REG); \ outb(0, DMA1_CLR_MASK_REG); \ - outb(0, DMA2_CLR_MASK_REG); \ - outb(DMA_MODE_CASCADE, DMA2_MODE_REG) - + outb(0, DMA2_CLR_MASK_REG) extern unsigned long alpha_irq_mask; diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/machvec.h linux/arch/alpha/kernel/machvec.h --- v2.1.125/linux/arch/alpha/kernel/machvec.h Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/machvec.h Mon Oct 12 11:40:12 1998 @@ -27,8 +27,7 @@ #define CAT1(x,y) x##y #define CAT(x,y) CAT1(x,y) -#define DO_DEFAULT_RTC \ - rtc_port: 0x70, rtc_addr: 0x80, rtc_bcd: 0 +#define DO_DEFAULT_RTC rtc_port: 0x70 #define DO_EV4_MMU \ max_asn: EV4_MAX_ASN, \ diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.1.125/linux/arch/alpha/kernel/process.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/process.c Mon Oct 12 11:40:12 1998 @@ -181,6 +181,9 @@ return; } + if (alpha_using_srm) + srm_paging_stop(); + halt(); } diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.1.125/linux/arch/alpha/kernel/proto.h Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/proto.h Mon Oct 12 11:40:12 1998 @@ -143,6 +143,7 @@ /* time.c */ extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs); +extern unsigned long est_cycle_freq; /* smc37c93x.c */ extern void SMC93x_Init(void); @@ -172,5 +173,12 @@ extern void entUna(void); /* process.c */ -void generic_kill_arch (int mode, char *reboot_cmd); -void cpu_idle(void *) __attribute__((noreturn)); +extern void generic_kill_arch (int mode, char *reboot_cmd); +extern void cpu_idle(void *) __attribute__((noreturn)); + +/* ptrace.c */ +extern int ptrace_set_bpt (struct task_struct *child); +extern int ptrace_cancel_bpt (struct task_struct *child); + +/* ../mm/init.c */ +void srm_paging_stop(void); diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c --- v2.1.125/linux/arch/alpha/kernel/ptrace.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/ptrace.c Mon Oct 12 11:40:12 1998 @@ -12,27 +12,26 @@ #include #include #include +#include #include #include #include +#include "proto.h" + +#define DEBUG DBG_MEM #undef DEBUG #ifdef DEBUG - enum { DBG_MEM = (1<<0), DBG_BPT = (1<<1), DBG_MEM_ALL = (1<<2) }; - -int debug_mask = DBG_BPT; - -# define DBG(fac,args) {if ((fac) & debug_mask) printk args;} - +#define DBG(fac,args) {if ((fac) & DEBUG) printk args;} #else -# define DBG(fac,args) +#define DBG(fac,args) #endif #define BREAKINST 0x00000080 /* call_pal bpt */ @@ -45,33 +44,26 @@ /* * Processes always block with the following stack-layout: * - * +================================+ -------------------------- - * | PALcode saved frame (ps, pc, | ^ ^ - * | gp, a0, a1, a2) | | | - * +================================+ | struct pt_regs | - * | | | | - * | frame generated by SAVE_ALL | | | - * | | v | P - * +================================+ | A - * | | ^ | G - * | frame saved by do_switch_stack | | struct switch_stack | E - * | | v | _ - * +================================+ | S - * | | | I - * | | | Z - * / / | E - * / / | - * | | | - * | | | - * | | v - * +================================+ <------------------------- - * task + PAGE_SIZE + * +================================+ <---- task + 2*PAGE_SIZE + * | PALcode saved frame (ps, pc, | ^ + * | gp, a0, a1, a2) | | + * +================================+ | struct pt_regs + * | | | + * | frame generated by SAVE_ALL | | + * | | v + * +================================+ + * | | ^ + * | frame saved by do_switch_stack | | struct switch_stack + * | | v + * +================================+ */ -#define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \ +#define PT_REG(reg) (PAGE_SIZE*2 - sizeof(struct pt_regs) \ + (long)&((struct pt_regs *)0)->reg) -#define SW_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \ - - sizeof(struct switch_stack) \ + +#define SW_REG(reg) (PAGE_SIZE*2 - sizeof(struct pt_regs) \ + - sizeof(struct switch_stack) \ + (long)&((struct switch_stack *)0)->reg) + /* * The following table maps a register index into the stack offset at * which the register is saved. Register indices are 0-31 for integer @@ -80,10 +72,10 @@ * get_reg/put_reg below). */ enum { - REG_R0 = 0, REG_F0 = 32, REG_PC = 64 + REG_R0 = 0, REG_F0 = 32, REG_FPCR = 63, REG_PC = 64 }; -static unsigned short regoff[] = { +static int regoff[] = { PT_REG( r0), PT_REG( r1), PT_REG( r2), PT_REG( r3), PT_REG( r4), PT_REG( r5), PT_REG( r6), PT_REG( r7), PT_REG( r8), SW_REG( r9), SW_REG( r10), SW_REG( r11), @@ -106,38 +98,40 @@ static long zero; /* - * Get contents of register REGNO in task TASK. + * Get address of register REGNO in task TASK. */ -static inline long get_reg(struct task_struct * task, long regno) +static long * +get_reg_addr(struct task_struct * task, unsigned long regno) { long *addr; if (regno == 30) { addr = &task->tss.usp; - } else if (regno == 31) { + } else if (regno == 31 || regno > 64) { zero = 0; addr = &zero; } else { - addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task); + addr = (long *)((long)task + regoff[regno]); } - return *addr; + return addr; } /* - * Write contents of register REGNO in task TASK. + * Get contents of register REGNO in task TASK. */ -static inline int put_reg(struct task_struct *task, long regno, long data) +static inline long +get_reg(struct task_struct * task, unsigned long regno) { - long *addr, zero; + return *get_reg_addr(task, regno); +} - if (regno == 30) { - addr = &task->tss.usp; - } else if (regno == 31) { - addr = &zero; - } else { - addr = (long *) (regoff[regno] + PAGE_SIZE + (long)task); - } - *addr = data; +/* + * Write contents of register REGNO in task TASK. + */ +static inline int +put_reg(struct task_struct *task, unsigned long regno, long data) +{ + *get_reg_addr(task, regno) = data; return 0; } @@ -147,8 +141,9 @@ * 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) +static unsigned long +get_long(struct task_struct * tsk, struct vm_area_struct * vma, + unsigned long addr) { pgd_t * pgdir; pmd_t * pgmiddle; @@ -199,8 +194,9 @@ * Now keeps R/W state of 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) +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; @@ -250,8 +246,8 @@ flush_tlb(); } -static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, - unsigned long addr) +static struct vm_area_struct * +find_extend_vma(struct task_struct * tsk, unsigned long addr) { struct vm_area_struct * vma; @@ -274,8 +270,8 @@ * 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) +static int +read_long(struct task_struct * tsk, unsigned long addr, unsigned long * result) { struct vm_area_struct * vma = find_extend_vma(tsk, addr); @@ -315,8 +311,8 @@ * 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) +static int +write_long(struct task_struct * tsk, unsigned long addr, unsigned long data) { struct vm_area_struct * vma = find_extend_vma(tsk, addr); @@ -349,8 +345,8 @@ /* * Read a 32bit int from address space TSK. */ -static int read_int(struct task_struct * tsk, unsigned long addr, - unsigned int *data) +static int +read_int(struct task_struct * tsk, unsigned long addr, unsigned int *data) { unsigned long l, align; int res; @@ -376,8 +372,8 @@ * For simplicity, do a read-modify-write of the 64bit word that * contains the 32bit word that we are about to write. */ -static int write_int(struct task_struct * tsk, unsigned long addr, - unsigned int data) +static int +write_int(struct task_struct * tsk, unsigned long addr, unsigned int data) { unsigned long l, align; int res; @@ -400,7 +396,8 @@ /* * Set breakpoint. */ -int ptrace_set_bpt(struct task_struct * child) +int +ptrace_set_bpt(struct task_struct * child) { int displ, i, res, reg_b, nsaved = 0; u32 insn, op_code; @@ -422,31 +419,31 @@ * branch (emulation can be tricky for fp branches). */ displ = ((s32)(insn << 11)) >> 9; - child->tss.debugreg[nsaved++] = pc + 4; + child->tss.bpt_addr[nsaved++] = pc + 4; if (displ) /* guard against unoptimized code */ - child->tss.debugreg[nsaved++] = pc + 4 + displ; + child->tss.bpt_addr[nsaved++] = pc + 4 + displ; DBG(DBG_BPT, ("execing branch\n")); } else if (op_code == 0x1a) { reg_b = (insn >> 16) & 0x1f; - child->tss.debugreg[nsaved++] = get_reg(child, reg_b); + child->tss.bpt_addr[nsaved++] = get_reg(child, reg_b); DBG(DBG_BPT, ("execing jump\n")); } else { - child->tss.debugreg[nsaved++] = pc + 4; + child->tss.bpt_addr[nsaved++] = pc + 4; DBG(DBG_BPT, ("execing normal insn\n")); } /* install breakpoints: */ for (i = 0; i < nsaved; ++i) { - res = read_int(child, child->tss.debugreg[i], &insn); + res = read_int(child, child->tss.bpt_addr[i], &insn); if (res < 0) return res; - child->tss.debugreg[i + 2] = insn; - DBG(DBG_BPT, (" -> next_pc=%lx\n", child->tss.debugreg[i])); - res = write_int(child, child->tss.debugreg[i], BREAKINST); + child->tss.bpt_insn[i] = insn; + DBG(DBG_BPT, (" -> next_pc=%lx\n", child->tss.bpt_addr[i])); + res = write_int(child, child->tss.bpt_addr[i], BREAKINST); if (res < 0) return res; } - child->tss.debugreg[4] = nsaved; + child->tss.bpt_nsaved = nsaved; return 0; } @@ -454,11 +451,12 @@ * 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 +ptrace_cancel_bpt(struct task_struct * child) { - int i, nsaved = child->tss.debugreg[4]; + int i, nsaved = child->tss.bpt_nsaved; - child->tss.debugreg[4] = 0; + child->tss.bpt_nsaved = 0; if (nsaved > 2) { printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); @@ -466,16 +464,18 @@ } for (i = 0; i < nsaved; ++i) { - write_int(child, child->tss.debugreg[i], - child->tss.debugreg[i + 2]); + write_int(child, child->tss.bpt_addr[i], + child->tss.bpt_insn[i]); } return (nsaved != 0); } -asmlinkage long sys_ptrace(long request, long pid, long addr, long data, - int a4, int a5, struct pt_regs regs) +asmlinkage long +sys_ptrace(long request, long pid, long addr, long data, + int a4, int a5, struct pt_regs regs) { struct task_struct *child; + unsigned long tmp; long ret; lock_kernel(); @@ -540,9 +540,7 @@ switch (request) { /* When I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - + case PTRACE_PEEKDATA: ret = read_long(child, addr, &tmp); DBG(DBG_MEM, ("peek %#lx->%#lx\n", addr, tmp)); if (ret < 0) @@ -550,13 +548,12 @@ regs.r0 = 0; /* special return: no errors */ ret = tmp; goto out; - } - /* read register number ADDR. */ + /* Read register number ADDR. */ case PTRACE_PEEKUSR: regs.r0 = 0; /* special return: no errors */ - DBG(DBG_MEM, ("peek $%ld=%#lx\n", addr, regs.r0)); ret = get_reg(child, addr); + DBG(DBG_MEM, ("peek $%ld->%#lx\n", addr, ret)); goto out; /* When I and D space are separate, this will have to be fixed. */ @@ -573,7 +570,7 @@ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: { /* restart after signal. */ + case PTRACE_CONT: /* restart after signal. */ ret = -EIO; if ((unsigned long) data > _NSIG) goto out; @@ -587,14 +584,13 @@ ptrace_cancel_bpt(child); ret = data; 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: { + case PTRACE_KILL: if (child->state != TASK_ZOMBIE) { wake_up_process(child); child->exit_code = SIGKILL; @@ -603,22 +599,20 @@ ptrace_cancel_bpt(child); ret = 0; goto out; - } - case PTRACE_SINGLESTEP: { /* execute single instruction. */ + case PTRACE_SINGLESTEP: /* execute single instruction. */ ret = -EIO; if ((unsigned long) data > _NSIG) goto out; - child->tss.debugreg[4] = -1; /* mark single-stepping */ + child->tss.bpt_nsaved = -1; /* mark single-stepping */ 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. */ + case PTRACE_DETACH: /* detach a process that was attached. */ ret = -EIO; if ((unsigned long) data > _NSIG) goto out; @@ -632,7 +626,6 @@ ptrace_cancel_bpt(child); ret = 0; goto out; - } default: ret = -EIO; @@ -643,7 +636,8 @@ return ret; } -asmlinkage void syscall_trace(void) +asmlinkage void +syscall_trace(void) { if ((current->flags & (PF_PTRACED|PF_TRACESYS)) != (PF_PTRACED|PF_TRACESYS)) diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.1.125/linux/arch/alpha/kernel/setup.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/setup.c Mon Oct 12 11:40:12 1998 @@ -467,19 +467,22 @@ vec = eb66_vecs[eb66_indices[member]]; break; case ST_DEC_1000: - if (cpu == EV5_CPU) + cpu &= 0xffffffff; + if (cpu == EV5_CPU || cpu == EV56_CPU) vec = &mikasa_primo_mv; else vec = &mikasa_mv; break; case ST_DEC_NORITAKE: - if (cpu == EV5_CPU) + cpu &= 0xffffffff; + if (cpu == EV5_CPU || cpu == EV56_CPU) vec = &noritake_primo_mv; else vec = &noritake_mv; break; case ST_DEC_2100_A500: - if (cpu == EV5_CPU) + cpu &= 0xffffffff; + if (cpu == EV5_CPU || cpu == EV56_CPU) vec = &sable_gamma_mv; else vec = &sable_mv; @@ -678,7 +681,7 @@ "system variation\t: %s\n" "system revision\t\t: %ld\n" "system serial number\t: %s\n" - "cycle frequency [Hz]\t: %lu\n" + "cycle frequency [Hz]\t: %lu %s\n" "timer frequency [Hz]\t: %lu.%02lu\n" "page size [bytes]\t: %ld\n" "phys. address bits\t: %ld\n" @@ -691,7 +694,8 @@ (char*)cpu->serial_no, systype_name, sysvariation_name, hwrpb->sys_revision, (char*)hwrpb->ssn, - hwrpb->cycle_freq, + hwrpb->cycle_freq ? : est_cycle_freq, + hwrpb->cycle_freq ? "" : "est.", hwrpb->intr_freq / 4096, (100 * hwrpb->intr_freq / 4096) % 100, hwrpb->pagesize, @@ -703,8 +707,8 @@ platform_string()); #ifdef __SMP__ - return len + smp_info(buffer+len); -#else - return len; + len += smp_info(buffer+len); #endif + + return len; } diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.1.125/linux/arch/alpha/kernel/signal.c Tue Jun 23 10:01:19 1998 +++ linux/arch/alpha/kernel/signal.c Mon Oct 12 11:40:12 1998 @@ -33,9 +33,6 @@ asmlinkage int do_signal(sigset_t *, struct pt_regs *, struct switch_stack *, unsigned long, unsigned long); -extern int ptrace_set_bpt (struct task_struct *child); -extern int ptrace_cancel_bpt (struct task_struct *child); - /* * The OSF/1 sigprocmask calling sequence is different from the diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/smc37c93x.c linux/arch/alpha/kernel/smc37c93x.c --- v2.1.125/linux/arch/alpha/kernel/smc37c93x.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/smc37c93x.c Mon Oct 12 11:40:12 1998 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -86,21 +87,28 @@ unsigned long indexPort; unsigned long dataPort; + int i; + 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; +#define NUM_RETRIES 5 + + for (i = 0; i < NUM_RETRIES; i++) + { + 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); + break; + } + else + udelay(100); } - return baseAddr; + return (i != NUM_RETRIES) ? baseAddr : 0L; } static void __init SMCRunState(unsigned long baseAddr) diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.1.125/linux/arch/alpha/kernel/smp.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/smp.c Mon Oct 12 11:40:12 1998 @@ -39,6 +39,7 @@ unsigned int boot_cpu_id = 0; static int smp_activated = 0; +static unsigned long ipicnt[NR_CPUS] = {0,}; /* IPI counts */ int smp_found_config = 0; /* Have we found an SMP box */ static int max_cpus = -1; @@ -619,7 +620,6 @@ { tbia(); clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - mb(); return 0; } @@ -627,12 +627,9 @@ local_flush_tlb_mm(unsigned int this_cpu) { struct mm_struct * mm = ipi_msg_flush_tb.p.flush_mm; - if (mm != current->mm) - flush_tlb_other(mm); - else + if (mm == current->mm) flush_tlb_current(mm); clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - mb(); return 0; } @@ -642,12 +639,9 @@ struct vm_area_struct * vma = ipi_msg_flush_tb.p.flush_vma; struct mm_struct * mm = vma->vm_mm; - if (mm != current->mm) - flush_tlb_other(mm); - else + if (mm == current->mm) flush_tlb_current_page(mm, vma, ipi_msg_flush_tb.flush_addr); clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - mb(); return 0; } @@ -701,7 +695,7 @@ volatile int * pending_ipis = &ipi_bits[this_cpu]; int ops; - mb(); + mb(); /* Order bit setting and interrupt. */ #if 0 printk("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n", this_cpu, *pending_ipis, regs->pc); @@ -711,10 +705,10 @@ for (first = 0; (ops & 1) == 0; ++first, ops >>= 1) ; /* look for the first thing to do */ clear_bit(first, pending_ipis); - mb(); + mb(); /* Order bit clearing and data access. */ if ((*ipi_func[first])(this_cpu)) - printk("%d\n", first); - mb(); + printk("%d\n", first); + mb(); /* Order data access and bit clearing. */ } if (hwrpb->txrdy) secondary_console_message(); @@ -726,19 +720,26 @@ int i; unsigned int j; + mb(); /* Order out-of-band data and bit setting. */ for (i = 0, j = 1; i < NR_CPUS; ++i, j += j) { if ((to_whom & j) == 0) continue; set_bit(operation, &ipi_bits[i]); - mb(); + mb(); /* Order bit setting and interrupt. */ wripir(i); } } -int smp_info(char *buffer) +int +smp_info(char *buffer) { - return sprintf(buffer, "CPUs probed %d active %d map 0x%x\n", - smp_num_probed, smp_num_cpus, cpu_present_map); + int i; + unsigned long sum = 0; + for (i = 0; i < NR_CPUS; i++) + sum += ipicnt[i]; + + return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n", + smp_num_probed, smp_num_cpus, cpu_present_map, sum); } /* wrapper for call from panic() */ @@ -763,19 +764,22 @@ unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id()); int timeout = 10000; + spin_lock_own(&kernel_flag, "flush_tlb_all"); + ipi_msg_flush_tb.flush_tb_mask = to_whom; send_ipi_message(to_whom, TLB_ALL); tbia(); while (ipi_msg_flush_tb.flush_tb_mask) { - if (--timeout < 0) { - printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; - break; - } - udelay(100); - ; /* Wait for all clear from other CPUs. */ + if (--timeout < 0) { + printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n", + smp_processor_id(), + ipi_msg_flush_tb.flush_tb_mask); + ipi_msg_flush_tb.flush_tb_mask = 0; + break; + } + /* Wait for all clear from other CPUs. */ + udelay(100); } } @@ -785,6 +789,8 @@ unsigned int to_whom = cpu_present_map ^ (1 << smp_processor_id()); int timeout = 10000; + spin_lock_own(&kernel_flag, "flush_tlb_mm"); + ipi_msg_flush_tb.p.flush_mm = mm; ipi_msg_flush_tb.flush_tb_mask = to_whom; send_ipi_message(to_whom, TLB_MM); @@ -814,6 +820,8 @@ struct mm_struct * mm = vma->vm_mm; int timeout = 10000; + spin_lock_own(&kernel_flag, "flush_tlb_page"); + ipi_msg_flush_tb.p.flush_vma = vma; ipi_msg_flush_tb.flush_addr = addr; ipi_msg_flush_tb.flush_tb_mask = to_whom; @@ -849,6 +857,8 @@ timeout = 10000; to_whom = cpu_present_map ^ (1 << smp_processor_id()); + spin_lock_own(&kernel_flag, "flush_tlb_range"); + ipi_msg_flush_tb.p.flush_mm = mm; ipi_msg_flush_tb.flush_tb_mask = to_whom; send_ipi_message(to_whom, TLB_MM); @@ -871,11 +881,51 @@ } #if DEBUG_SPINLOCK -void spin_lock(spinlock_t * lock) + +#ifdef MANAGE_SPINLOCK_IPL + +static inline long +spinlock_raise_ipl(spinlock_t * lock) +{ + long min_ipl = lock->target_ipl; + long last_ipl = swpipl(7); + if (last_ipl < 7 && min_ipl < 7) + setipl(min_ipl < last_ipl ? last_ipl : min_ipl); + return last_ipl; +} + +static inline void +spinlock_restore_ipl(long prev) +{ + setipl(prev); +} + +#else + +#define spinlock_raise_ipl(LOCK) 0 +#define spinlock_restore_ipl(PREV) ((void)0) + +#endif /* MANAGE_SPINLOCK_IPL */ + +void +spin_unlock(spinlock_t * lock) +{ + long old_ipl = lock->saved_ipl; + mb(); + lock->lock = 0; + spinlock_restore_ipl(old_ipl); +} + +void +spin_lock(spinlock_t * lock) { long tmp; - long stuck; + long stuck = 1<<27; void *inline_pc = __builtin_return_address(0); + unsigned long started = jiffies; + int printed = 0; + int cpu = smp_processor_id(); + long old_ipl = spinlock_raise_ipl(lock); try_again: @@ -885,15 +935,15 @@ of this object file's text section so as to perfect branch prediction. */ __asm__ __volatile__( - "1: ldq_l %0,%1\n" + "1: ldl_l %0,%1\n" " subq %2,1,%2\n" " blbs %0,2f\n" " or %0,1,%0\n" - " stq_c %0,%1\n" + " stl_c %0,%1\n" " beq %0,3f\n" "4: mb\n" ".section .text2,\"ax\"\n" - "2: ldq %0,%1\n" + "2: ldl %0,%1\n" " subq %2,1,%2\n" "3: blt %2,4b\n" " blbs %0,2b\n" @@ -905,13 +955,43 @@ : "2" (stuck)); if (stuck < 0) { - printk("spinlock stuck at %p (cur=%p, own=%p, prev=%p)\n", - inline_pc, current, lock->task, lock->previous); + if (!printed) { + printk("spinlock stuck at %p(%d) owner %s at %p\n", + inline_pc, cpu, lock->task->comm, + lock->previous); + printed = 1; + } + stuck = 1<<30; goto try_again; - } else { - lock->previous = inline_pc; + } + + /* Exiting. Got the lock. */ + lock->saved_ipl = old_ipl; + lock->on_cpu = cpu; + lock->previous = inline_pc; + lock->task = current; + + if (printed) { + printk("spinlock grabbed at %p(%d) %ld ticks\n", + inline_pc, cpu, jiffies - started); + } +} + +int +spin_trylock(spinlock_t * lock) +{ + long old_ipl = spinlock_raise_ipl(lock); + int ret; + if ((ret = !test_and_set_bit(0, lock))) { + mb(); + lock->saved_ipl = old_ipl; + lock->on_cpu = smp_processor_id(); + lock->previous = __builtin_return_address(0); lock->task = current; + } else { + spinlock_restore_ipl(old_ipl); } + return ret; } #endif /* DEBUG_SPINLOCK */ @@ -930,22 +1010,21 @@ __asm__ __volatile__( "1: ldl_l %1,%0\n" " blbs %1,6f\n" - " or %1,1,%2\n" - " stl_c %2,%0\n" - " beq %2,6f\n" " blt %1,8f\n" + " mov 1,%1\n" + " stl_c %1,%0\n" + " beq %1,6f\n" "4: mb\n" ".section .text2,\"ax\"\n" - "6: ldl %1,%0\n" - " blt %3,4b # debug\n" + "6: blt %3,4b # debug\n" " subl %3,1,%3 # debug\n" + " ldl %1,%0\n" " blbs %1,6b\n" - " br 1b\n" - "8: ldl %1,%0\n" - " blt %4,4b # debug\n" + "8: blt %4,4b # debug\n" " subl %4,1,%4 # debug\n" + " ldl %1,%0\n" " blt %1,8b\n" - " br 4b\n" + " br 1b\n" ".previous" : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy) , "=&r" (stuck_lock), "=&r" (stuck_reader) diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c --- v2.1.125/linux/arch/alpha/kernel/sys_jensen.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/sys_jensen.c Mon Oct 12 11:40:12 1998 @@ -128,7 +128,7 @@ BUS(jensen), machine_check: jensen_machine_check, max_dma_address: ALPHA_MAX_DMA_ADDRESS, - rtc_port: 0x170, rtc_addr: 0, rtc_bcd: 1, + rtc_port: 0x170, nr_irqs: 16, irq_probe_mask: _PROBE_MASK(16), diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c --- v2.1.125/linux/arch/alpha/kernel/sys_ruffian.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/sys_ruffian.c Mon Oct 12 11:40:12 1998 @@ -247,8 +247,7 @@ struct alpha_machine_vector ruffian_mv __initmv = { vector_name: "Ruffian", DO_EV5_MMU, - /* RUFFIAN always uses BCD, like a PeeCee. */ - rtc_port: 0x70, rtc_addr: 0x80, rtc_bcd: 1, + DO_DEFAULT_RTC, /* For the moment, do not use BWIO on RUFFIAN. */ IO(PYXIS,pyxis,pyxis), DO_PYXIS_BUS, diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/sys_sx164.c linux/arch/alpha/kernel/sys_sx164.c --- v2.1.125/linux/arch/alpha/kernel/sys_sx164.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/sys_sx164.c Mon Oct 12 11:40:12 1998 @@ -103,7 +103,10 @@ static void sx164_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(DMA_MODE_CASCADE, DMA2_MODE_REG); + outb(0, DMA2_MASK_REG); if (alpha_using_srm) { alpha_mv.update_irq_hw = sx164_srm_update_irq_hw; diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.1.125/linux/arch/alpha/kernel/time.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/kernel/time.c Mon Oct 12 11:40:12 1998 @@ -62,6 +62,8 @@ time_t last_rtc_update; } state; +unsigned long est_cycle_freq; + static inline __u32 rpcc(void) { @@ -162,7 +164,7 @@ * drivers depend on them being initialized (e.g., joystick driver). */ -/* It is (normally) only counter 1 that presents config problems, so +/* It is (normally) only counter 0 that presents config problems, so provide this support function to do the rest of the job. */ void inline @@ -184,12 +186,20 @@ static inline void rtc_init_pit (void) { + unsigned char control; + /* Setup interval timer if /dev/rtc is being used */ outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ outb(LATCH & 0xff, 0x40); /* LSB */ outb(LATCH >> 8, 0x40); /* MSB */ request_region(0x40, 0x20, "timer"); /* reserve pit */ + /* Turn off RTC interrupts before /dev/rtc is initialized */ + control = CMOS_READ(RTC_CONTROL); + control &= ~(RTC_PIE | RTC_AIE | RTC_UIE); + CMOS_WRITE(control, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + init_pit_rest(); } #endif @@ -197,11 +207,25 @@ void generic_init_pit (void) { - int x; - if ((x = (CMOS_READ(RTC_FREQ_SELECT) & 0x3f)) != 0x26) { + unsigned char x; + + /* Reset periodic interrupt frequency. */ + x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f; + if (x != 0x26 && x != 0x19 && x != 0x06) { printk("Setting RTC_FREQ to 1024 Hz (%x)\n", x); CMOS_WRITE(0x26, RTC_FREQ_SELECT); } + + /* Turn on periodic interrupts. */ + x = CMOS_READ(RTC_CONTROL); + if (!(x & RTC_PIE)) { + printk("Turning on RTC interrupts.\n"); + x |= RTC_PIE; + x &= ~(RTC_AIE | RTC_UIE); + CMOS_WRITE(x, RTC_CONTROL); + } + CMOS_READ(RTC_INTR_FLAGS); + request_region(RTC_PORT(0), 0x10, "timer"); /* reserve rtc */ /* Turn off the PIT. */ @@ -223,11 +247,9 @@ void time_init(void) { -#ifdef CONFIG_RTC - unsigned char save_control; -#endif void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; + unsigned long cycle_freq; /* Initialize the timers. */ init_pit(); @@ -246,16 +268,17 @@ /* If our cycle frequency isn't valid, go another round and give a guess at what it should be. */ - if (hwrpb->cycle_freq == 0) { + cycle_freq = hwrpb->cycle_freq; + if (cycle_freq == 0) { printk("HWRPB cycle frequency bogus. Estimating... "); do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); cc2 = rpcc(); - hwrpb->cycle_freq = cc2 - cc1; + est_cycle_freq = cycle_freq = cc2 - cc1; cc1 = cc2; - printk("%lu Hz\n", hwrpb->cycle_freq); + printk("%lu Hz\n", cycle_freq); } /* From John Bowman : allow the values @@ -300,18 +323,8 @@ state.last_time = cc1; state.scaled_ticks_per_cycle - = ((unsigned long) HZ << FIX_SHIFT) / hwrpb->cycle_freq; + = ((unsigned long) HZ << FIX_SHIFT) / cycle_freq; state.last_rtc_update = 0; - -#ifdef CONFIG_RTC - /* turn off RTC interrupts before /dev/rtc is initialized */ - save_control = CMOS_READ(RTC_CONTROL); - save_control &= ~RTC_PIE; - save_control &= ~RTC_AIE; - save_control &= ~RTC_UIE; - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); -#endif /* setup timer */ irq_handler = timer_interrupt; diff -u --recursive --new-file v2.1.125/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.1.125/linux/arch/alpha/kernel/traps.c Tue Aug 18 22:02:02 1998 +++ linux/arch/alpha/kernel/traps.c Mon Oct 12 11:40:12 1998 @@ -149,8 +149,6 @@ unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { - extern int ptrace_cancel_bpt (struct task_struct *who); - lock_kernel(); die_if_kernel("Instruction fault", ®s, type, 0); switch (type) { @@ -558,11 +556,12 @@ #define OP_INT_MASK ( 1L << 0x28 | 1L << 0x2c /* ldl stl */ \ | 1L << 0x29 | 1L << 0x2d /* ldq stq */ \ - | 1L << 0x0c | 1L << 0x0d ) /* ldwu stw */ + | 1L << 0x0c | 1L << 0x0d /* ldwu stw */ \ + | 1L << 0x0a | 1L << 0x0e ) /* ldbu stb */ #define OP_WRITE_MASK ( 1L << 0x26 | 1L << 0x27 /* sts stt */ \ | 1L << 0x2c | 1L << 0x2d /* stl stq */ \ - | 1L << 0xd ) /* stw */ + | 1L << 0x0d | 1L << 0x0e ) /* stw stb */ #define R(x) ((size_t) &((struct pt_regs *)0)->x) diff -u --recursive --new-file v2.1.125/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile --- v2.1.125/linux/arch/alpha/lib/Makefile Tue Aug 18 22:02:02 1998 +++ linux/arch/alpha/lib/Makefile Mon Oct 12 11:40:12 1998 @@ -7,7 +7,8 @@ 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 \ - csum_ipv6_magic.o strcasecmp.o + csum_ipv6_magic.o strcasecmp.o \ + srm_dispatch.o srm_fixup.o srm_puts.o srm_printk.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff -u --recursive --new-file v2.1.125/linux/arch/alpha/lib/srm_dispatch.S linux/arch/alpha/lib/srm_dispatch.S --- v2.1.125/linux/arch/alpha/lib/srm_dispatch.S Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/srm_dispatch.S Mon Oct 12 11:40:12 1998 @@ -0,0 +1,43 @@ +/* + * arch/alpha/lib/srm_dispatch.S + */ + +.globl srm_dispatch +.ent srm_dispatch +srm_dispatch: + .frame $30,30,$26 + subq $30,80,$30 + stq $26,0($30) + stq $8,8($30) + stq $9,16($30) + stq $10,24($30) + stq $11,32($30) + stq $12,40($30) + stq $13,48($30) + stq $14,56($30) + stq $15,64($30) + stq $29,72($30) + .mask 0x2400FF00, -80 + .prologue 0 + + ldq $1,hwrpb + ldq $2,0xc0($1) /* crb offset */ + addq $2,$1,$2 /* crb */ + ldq $27,0($2) /* dispatch procedure value */ + + ldq $2,8($27) /* dispatch call address */ + jsr $26,($2) /* call it (weird VMS call seq) */ + + ldq $26,0($30) + ldq $8,8($30) + ldq $9,16($30) + ldq $10,24($30) + ldq $11,32($30) + ldq $12,40($30) + ldq $13,48($30) + ldq $14,56($30) + ldq $15,64($30) + ldq $29,72($30) + addq $30,80,$30 + ret $31,($26),1 +.end srm_dispatch diff -u --recursive --new-file v2.1.125/linux/arch/alpha/lib/srm_fixup.S linux/arch/alpha/lib/srm_fixup.S --- v2.1.125/linux/arch/alpha/lib/srm_fixup.S Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/srm_fixup.S Mon Oct 12 11:40:12 1998 @@ -0,0 +1,42 @@ +/* + * arch/alpha/lib/srm_fixup.S + */ + +.globl srm_fixup +.ent srm_fixup +srm_fixup: + .frame $30,30,$26 + subq $30,80,$30 + stq $26,0($30) + stq $8,8($30) + stq $9,16($30) + stq $10,24($30) + stq $11,32($30) + stq $12,40($30) + stq $13,48($30) + stq $14,56($30) + stq $15,64($30) + stq $29,72($30) + .mask 0x2400FF00, -80 + .prologue 0 + + ldq $2,0xc0($17) /* crb offset */ + addq $2,$1,$2 /* crb */ + ldq $27,16($2) /* fixup procedure value */ + + ldq $2,8($27) /* dispatch call address */ + jsr $26,($2) /* call it (weird VMS call seq) */ + + ldq $26,0($30) + ldq $8,8($30) + ldq $9,16($30) + ldq $10,24($30) + ldq $11,32($30) + ldq $12,40($30) + ldq $13,48($30) + ldq $14,56($30) + ldq $15,64($30) + ldq $29,72($30) + addq $30,80,$30 + ret $31,($26),1 +.end srm_fixup diff -u --recursive --new-file v2.1.125/linux/arch/alpha/lib/srm_printk.c linux/arch/alpha/lib/srm_printk.c --- v2.1.125/linux/arch/alpha/lib/srm_printk.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/srm_printk.c Mon Oct 12 11:40:12 1998 @@ -0,0 +1,21 @@ +/* + * arch/alpha/lib/srm_printk.c + */ + +#include +#include + +long +srm_printk(const char *fmt, ...) +{ + static char buf[1024]; + va_list args; + long i; + + va_start(args, fmt); + i = vsprintf(buf,fmt,args); + va_end(args); + + srm_puts(buf); + return i; +} diff -u --recursive --new-file v2.1.125/linux/arch/alpha/lib/srm_puts.c linux/arch/alpha/lib/srm_puts.c --- v2.1.125/linux/arch/alpha/lib/srm_puts.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/lib/srm_puts.c Mon Oct 12 11:40:12 1998 @@ -0,0 +1,34 @@ +/* + * arch/alpha/lib/srm_puts.c + */ + +#include +#include + +void +srm_puts(const char *str) +{ + /* Expand \n to \r\n as we go. */ + + while (*str) { + long len; + const char *e = str; + + if (*str == '\n') { + if (srm_dispatch(CCB_PUTS, 0, "\r", 1) < 0) + return; + ++e; + } + + e = strchr(e, '\n') ? : strchr(e, '\0'); + len = e - str; + + while (len > 0) { + long written = srm_dispatch(CCB_PUTS, 0, str, len); + if (written < 0) + return; + len -= written & 0xffffffff; + str += written & 0xffffffff; + } + } +} diff -u --recursive --new-file v2.1.125/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.1.125/linux/arch/alpha/mm/init.c Wed Sep 9 14:51:04 1998 +++ linux/arch/alpha/mm/init.c Mon Oct 12 11:40:12 1998 @@ -30,7 +30,7 @@ extern void die_if_kernel(char *,struct pt_regs *,long); extern void show_net_buffers(void); -struct thread_struct * original_pcb_ptr; +struct thread_struct original_pcb; #ifndef __SMP__ struct pgtable_cache_struct quicklists; @@ -193,47 +193,66 @@ unsigned long newptbr; struct memclust_struct * cluster; struct memdesc_struct * memdesc; + struct thread_struct *original_pcb_ptr; /* initialize mem_map[] */ start_mem = free_area_init(start_mem, end_mem); /* find free clusters, update mem_map[] accordingly */ memdesc = (struct memdesc_struct *) - (INIT_HWRPB->mddt_offset + (unsigned long) INIT_HWRPB); + (hwrpb->mddt_offset + (unsigned long) hwrpb); cluster = memdesc->cluster; for (i = memdesc->numclusters ; i > 0; i--, cluster++) { unsigned long pfn, nr; - if (cluster->usage & 1) + + /* Bit 0 is console/PALcode reserved. Bit 1 is + non-volatile memory -- we might want to mark + this for later */ + if (cluster->usage & 3) continue; pfn = cluster->start_pfn; nr = cluster->numpages; - /* non-volatile memory. We might want to mark this for later */ - if (cluster->usage & 2) - continue; - while (nr--) clear_bit(PG_reserved, &mem_map[pfn++].flags); } - /* unmap the console stuff: we don't need it, and we don't want it */ - /* Also set up the real kernel PCB while we're at it.. */ + /* Initialize the kernel's page tables. Linux puts the vptb in + the last slot of the L1 page table. */ memset((void *) ZERO_PAGE, 0, PAGE_SIZE); memset(swapper_pg_dir, 0, PAGE_SIZE); newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT; pgd_val(swapper_pg_dir[1023]) = (newptbr << 32) | pgprot_val(PAGE_KERNEL); + + /* Set the vptb. This is often done by the bootloader, but + shouldn't be required. */ + if (hwrpb->vptb != 0xfffffffe00000000) { + wrvptptr(0xfffffffe00000000); + hwrpb->vptb = 0xfffffffe00000000; + hwrpb_update_checksum(hwrpb); + } + + /* Also set up the real kernel PCB while we're at it. */ init_task.tss.ptbr = newptbr; init_task.tss.pal_flags = 1; /* set FEN, clear everything else */ init_task.tss.flags = 0; - original_pcb_ptr = - phys_to_virt((unsigned long)load_PCB(&init_task.tss)); -#if 0 -printk("OKSP 0x%lx OPTBR 0x%lx\n", - original_pcb_ptr->ksp, original_pcb_ptr->ptbr); -#endif - + original_pcb_ptr = load_PCB(&init_task.tss); tbia(); + + /* Save off the contents of the original PCB so that we can + restore the original console's page tables for a clean reboot. + + Note that the PCB is supposed to be a physical address, but + since KSEG values also happen to work, folks get confused. + Check this here. */ + + if ((unsigned long)original_pcb_ptr < PAGE_OFFSET) { + original_pcb_ptr = (struct thread_struct *) + phys_to_virt((unsigned long) original_pcb_ptr); + } + original_pcb = *original_pcb_ptr; + return start_mem; } @@ -250,18 +269,29 @@ current->tss.ptbr = init_task.tss.ptbr; current->tss.pal_flags = 1; current->tss.flags = 0; - -#if 0 -printk("paging_init_secondary: KSP 0x%lx PTBR 0x%lx\n", - current->tss.ksp, current->tss.ptbr); -#endif - load_PCB(¤t->tss); tbia(); return; } #endif /* __SMP__ */ + +#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) +void +srm_paging_stop (void) +{ + /* Move the vptb back to where the SRM console expects it. */ + swapper_pg_dir[1] = swapper_pg_dir[1023]; + tbia(); + wrvptptr(0x200000000); + hwrpb->vptb = 0x200000000; + hwrpb_update_checksum(hwrpb); + + /* Reload the page tables that the console had in use. */ + load_PCB(&original_pcb); + tbia(); +} +#endif #if DEBUG_POISON static void diff -u --recursive --new-file v2.1.125/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- v2.1.125/linux/arch/i386/kernel/bios32.c Mon Sep 28 10:51:33 1998 +++ linux/arch/i386/kernel/bios32.c Sun Oct 11 15:45:01 1998 @@ -346,7 +346,7 @@ * attempt to make use of direct access hints provided by the PCI BIOS). * * This should be close to trivial, but it isn't, because there are buggy - * chipsets (yes, you guessed it, by Intel) that have no class ID. + * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. */ __initfunc(int pci_sanity_check(struct pci_access *a)) { @@ -356,9 +356,9 @@ return 1; for(dfn=0; dfn < 0x100; dfn++) if ((!a->read_config_word(0, dfn, PCI_CLASS_DEVICE, &x) && - x == PCI_CLASS_BRIDGE_HOST) || + (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) || (!a->read_config_word(0, dfn, PCI_VENDOR_ID, &x) && - x == PCI_VENDOR_ID_INTEL)) + (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ))) return 1; DBG("PCI: Sanity check failed\n"); return 0; diff -u --recursive --new-file v2.1.125/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.1.125/linux/arch/i386/kernel/setup.c Fri Oct 9 13:27:05 1998 +++ linux/arch/i386/kernel/setup.c Wed Oct 14 11:39:25 1998 @@ -431,9 +431,9 @@ "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+", + { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75 - 200", "OverDrive PODP5V83", "Pentium MMX", NULL, NULL, - "Mobile Pentium 75+", "Mobile Pentium MMX", NULL, NULL, NULL, + "Mobile Pentium 75 - 200", "Mobile Pentium MMX", NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, { X86_VENDOR_INTEL, 6, { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", diff -u --recursive --new-file v2.1.125/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v2.1.125/linux/arch/i386/kernel/time.c Thu Jul 16 18:09:23 1998 +++ linux/arch/i386/kernel/time.c Fri Oct 9 12:16:19 1998 @@ -12,7 +12,29 @@ * precision CMOS clock update * 1996-05-03 Ingo Molnar * fixed time warps in do_[slow|fast]_gettimeoffset() + * 1998-09-05 (Various) + * More robust do_fast_gettimeoffset() algorithm implemented + * (works with APM, Cyrix 6x86MX and Centaur C6), + * monotonic gettimeofday() with fast_get_timeoffset(), + * drift-proof precision TSC calibration on boot + * (C. Scott Ananian , Andrew D. + * Balsa , Philip Gladstone ; + * ported from 2.0.35 Jumbo-9 by Michael Krause ). */ + +/* What about the "updated NTP code" stuff in 2.0 time.c? It's not in + * 2.1, perhaps it should be ported, too. + * + * What about the BUGGY_NEPTUN_TIMER stuff in do_slow_gettimeoffset()? + * Whatever it fixes, is it also fixed in the new code from the Jumbo + * patch, so that that code can be used instead? + * + * The CPU Hz should probably be displayed in check_bugs() together + * with the CPU vendor and type. Perhaps even only in MHz, though that + * takes away some of the fun of the new code :) + * + * - Michael Krause */ + #include #include #include @@ -41,100 +63,51 @@ #include "irq.h" extern int setup_x86_irq(int, struct irqaction *); -extern volatile unsigned long lost_ticks; -/* change this if you have some constant time drift */ -#define USECS_PER_JIFFY (1000020/HZ) +unsigned long cpu_hz; /* Detected as we calibrate the TSC */ + +/* Number of usecs that the last interrupt was delayed */ +static int delay_at_last_interrupt; + +static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ -#ifndef CONFIG_APM /* cycle counter may be unreliable */ -/* Cycle counter value at the previous timer interrupt.. */ -static struct { - unsigned long low; - unsigned long high; -} init_timer_cc, last_timer_cc; +/* Cached *multiplier* to convert TSC counts to microseconds. + * (see the equation below). + * Equal to 2^32 * (1 / (clocks per usec) ). + * Initialized in time_init. + */ +static unsigned long fast_gettimeoffset_quotient=0; static unsigned long do_fast_gettimeoffset(void) { register unsigned long eax asm("ax"); register unsigned long edx asm("dx"); - unsigned long tmp, quotient, low_timer; - - /* Last jiffy when do_fast_gettimeoffset() was called. */ - static unsigned long last_jiffies=0; - - /* - * Cached "1/(clocks per usec)*2^32" value. - * It has to be recalculated once each jiffy. - */ - static unsigned long cached_quotient=0; - - tmp = jiffies; - - quotient = cached_quotient; - low_timer = last_timer_cc.low; - if (last_jiffies != tmp) { - last_jiffies = tmp; - - /* Get last timer tick in absolute kernel time */ - eax = low_timer; - edx = last_timer_cc.high; - __asm__("subl "SYMBOL_NAME_STR(init_timer_cc)",%0\n\t" - "sbbl "SYMBOL_NAME_STR(init_timer_cc)"+4,%1" - :"=a" (eax), "=d" (edx) - :"0" (eax), "1" (edx)); - - /* - * Divide the 64-bit time with the 32-bit jiffy counter, - * getting the quotient in clocks. - * - * Giving quotient = "1/(average internal clocks per usec)*2^32" - * we do this '1/...' trick to get the 'mull' into the critical - * path. 'mull' is much faster than divl (10 vs. 41 clocks) - */ - __asm__("divl %2" - :"=a" (eax), "=d" (edx) - :"r" (tmp), - "0" (eax), "1" (edx)); - - edx = USECS_PER_JIFFY; - tmp = eax; - eax = 0; - - __asm__("divl %2" - :"=a" (eax), "=d" (edx) - :"r" (tmp), - "0" (eax), "1" (edx)); - cached_quotient = eax; - quotient = eax; - } - - /* Read the time counter */ - __asm__("rdtsc" : "=a" (eax), "=d" (edx)); + /* Read the Time Stamp Counter */ + __asm__("rdtsc" + :"=a" (eax), "=d" (edx)); /* .. relative to previous jiffy (32 bits is enough) */ edx = 0; - eax -= low_timer; + eax -= last_tsc_low; /* tsc_low delta */ /* - * Time offset = (USECS_PER_JIFFY * time_low) * quotient. - */ + * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient. + * = (tsc_low delta) / (clocks_per_usec) + * = (tsc_low delta) / (clocks_per_jiffy / usecs_per_jiffy) + * + * Using a mull instead of a divl saves up to 31 clock cycles + * in the critical path. + */ __asm__("mull %2" :"=a" (eax), "=d" (edx) - :"r" (quotient), + :"r" (fast_gettimeoffset_quotient), "0" (eax), "1" (edx)); - /* - * Due to possible jiffies inconsistencies, we need to check - * the result so that we'll get a timer that is monotonic. - */ - if (edx >= USECS_PER_JIFFY) - edx = USECS_PER_JIFFY-1; - - return edx; + /* our adjusted time offset in microseconds */ + return edx + delay_at_last_interrupt; } -#endif /* This function must be called with interrupts disabled * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs @@ -249,20 +222,11 @@ return count; } -#ifndef CONFIG_APM -/* - * this is only used if we have fast gettimeoffset: - */ -static void do_x86_get_fast_time(struct timeval * tv) -{ - do_gettimeofday(tv); -} -#endif - static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; /* - * This version of gettimeofday has near microsecond resolution. + * This version of gettimeofday has microsecond resolution + * and better than microsecond precision on fast x86 machines with TSC. */ void do_gettimeofday(struct timeval *tv) { @@ -272,20 +236,11 @@ cli(); *tv = xtime; tv->tv_usec += do_gettimeoffset(); - - /* - * xtime is atomically updated in timer_bh. lost_ticks is - * nonzero if the timer bottom half hasnt executed yet. - */ - if (lost_ticks) - tv->tv_usec += USECS_PER_JIFFY; - - restore_flags(flags); - if (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec++; } + restore_flags(flags); } void do_settimeofday(struct timeval *tv) @@ -311,13 +266,15 @@ sti(); } - /* * In order to set the CMOS clock precisely, set_rtc_mmss has to be * called 500 ms after the second nowtime has started, because when * nowtime is written into the registers of the CMOS clock, it will * jump to the next second precisely 500 ms later. Check the Motorola * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you'll only notice that after reboot! */ static int set_rtc_mmss(unsigned long nowtime) { @@ -354,8 +311,12 @@ } CMOS_WRITE(real_seconds,RTC_SECONDS); CMOS_WRITE(real_minutes,RTC_MINUTES); - } else + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); retval = -1; + } /* The following flags have to be released exactly in this order, * otherwise the DS12887 (popular MC146818A clone with integrated @@ -431,21 +392,37 @@ #endif } -#ifndef CONFIG_APM /* cycle counter may be unreliable */ /* * This is the same as the above, except we _also_ save the current - * cycle counter value at the time of the timer interrupt, so that + * Time Stamp Counter value at the time of the timer interrupt, so that * we later on can estimate the time of day more exactly. */ static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + int count, flags; + + /* It is important that these two operations happen almost at the + * same time. We do the RDTSC stuff first, since it's faster. To + * avoid any inconsistencies, we disable interrupts locally. + */ + + __save_flags(flags); + __cli(); /* read Pentium cycle counter */ __asm__("rdtsc" - :"=a" (last_timer_cc.low), - "=d" (last_timer_cc.high)); + :"=a" (last_tsc_low):: "eax", "edx"); + + outb_p(0x00, 0x43); /* latch the count ASAP */ + + count = inb_p(0x40); /* read the latched count */ + count |= inb(0x40) << 8; + + count = ((LATCH-1) - count) * TICK_SIZE; + delay_at_last_interrupt = (count + LATCH/2) / LATCH; + __restore_flags(flags); + timer_interrupt(irq, NULL, regs); } -#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 @@ -520,6 +497,80 @@ static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; +/* ------ Calibrate the TSC ------- + * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). + * Too much 64-bit arithmetic here to do this cleanly in C, and for + * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) + * output busy loop as low as possible. We avoid reading the CTC registers + * directly because of the awkward 8-bit access mechanism of the 82C54 + * device. + */ + +__initfunc(static unsigned long calibrate_tsc(void)) +{ + unsigned long retval; + + __asm__( /* set the Gate high, program CTC channel 2 for mode 0 + * (interrupt on terminal count mode), binary count, + * load 5 * LATCH count, (LSB and MSB) + * to begin countdown, read the TSC and busy wait. + * BTW LATCH is calculated in timex.h from the HZ value + */ + + /* Set the Gate high, disable speaker */ + "inb $0x61, %%al\n\t" /* Read port */ + "andb $0xfd, %%al\n\t" /* Turn off speaker Data */ + "orb $0x01, %%al\n\t" /* Set Gate high */ + "outb %%al, $0x61\n\t" /* Write port */ + + /* Now let's take care of CTC channel 2 */ + "movb $0xb0, %%al\n\t" /* binary, mode 0, LSB/MSB, ch 2*/ + "outb %%al, $0x43\n\t" /* Write to CTC command port */ + "movb $0x0c, %%al\n\t" + "outb %%al, $0x42\n\t" /* LSB of count */ + "movb $0xe9, %%al\n\t" + "outb %%al, $0x42\n\t" /* MSB of count */ + + /* Read the TSC; counting has just started */ + "rdtsc\n\t" + /* Move the value for safe-keeping. */ + "movl %%eax, %%ebx\n\t" + "movl %%edx, %%ecx\n\t" + + /* Busy wait. Only 50 ms wasted at boot time. */ + "0: inb $0x61, %%al\n\t" /* Read Speaker Output Port */ + "testb $0x20, %%al\n\t" /* Check CTC channel 2 output (bit 5) */ + "jz 0b\n\t" + + /* And read the TSC. 5 jiffies (50.00077ms) have elapsed. */ + "rdtsc\n\t" + + /* Great. So far so good. Store last TSC reading in + * last_tsc_low (only 32 lsb bits needed) */ + "movl %%eax, last_tsc_low\n\t" + /* And now calculate the difference between the readings. */ + "subl %%ebx, %%eax\n\t" + "sbbl %%ecx, %%edx\n\t" /* 64-bit subtract */ + /* but probably edx = 0 at this point (see below). */ + /* Now we have 5 * (TSC counts per jiffy) in eax. We want + * to calculate TSC->microsecond conversion factor. */ + + /* Note that edx (high 32-bits of difference) will now be + * zero iff CPU clock speed is less than 85 GHz. Moore's + * law says that this is likely to be true for the next + * 12 years or so. You will have to change this code to + * do a real 64-by-64 divide before that time's up. */ + "movl %%eax, %%ecx\n\t" + "xorl %%eax, %%eax\n\t" + "movl %1, %%edx\n\t" + "divl %%ecx\n\t" /* eax= 2^32 / (1 * TSC counts per microsecond) */ + /* Return eax for the use of fast_gettimeoffset */ + "movl %%eax, %0\n\t" + : "=r" (retval) + : "r" (5 * 1000020/HZ) + : /* we clobber: */ "ax", "bx", "cx", "dx", "cc", "memory"); + return retval; +} __initfunc(void time_init(void)) { @@ -527,36 +578,36 @@ xtime.tv_usec = 0; /* - * If we have APM enabled we can't currently depend - * on the cycle counter, because a suspend to disk - * will reset it. Somebody should come up with a - * better solution than to just disable the fast time - * code.. - */ -#ifndef CONFIG_APM - /* If we have the CPU hardware time counters, use them */ - if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) { + * If we have APM enabled or the CPU clock speed is variable + * (CPU stops clock on HLT or slows clock to save power) + * then the TSC timestamps may diverge by up to 1 jiffy from + * 'real time' but nothing will break. + * The most frequent case is that the CPU is "woken" from a halt + * state by the timer interrupt itself, so we get 0 error. In the + * rare cases where a driver would "wake" the CPU and request a + * timestamp, the maximum error is < 1 jiffy. But timestamps are + * still perfectly ordered. + * Note that the TSC counter will be reset if APM suspends + * to disk; this won't break the kernel, though, 'cuz we're + * smart. See devices/char/apm_bios.c. + */ + if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) { do_gettimeoffset = do_fast_gettimeoffset; - do_get_fast_time = do_x86_get_fast_time; - - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && - boot_cpu_data.x86 == 5 && - boot_cpu_data.x86_model == 0) { - /* turn on cycle counters during power down */ - __asm__ __volatile__ (" movl $0x83, %%ecx \n \ - rdmsr \n \ - orl $1,%%eax \n \ - wrmsr \n " - : : : "ax", "cx", "dx" ); - udelay(500); - } - - /* read Pentium cycle counter */ - __asm__("rdtsc" - :"=a" (init_timer_cc.low), - "=d" (init_timer_cc.high)); + do_get_fast_time = do_gettimeofday; irq0.handler = pentium_timer_interrupt; + fast_gettimeoffset_quotient = calibrate_tsc(); + + /* report CPU clock rate in Hz. + * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = + * clock/second. Our precision is about 100 ppm. + */ + { unsigned long eax=0, edx=1000000; + __asm__("divl %2" + :"=a" (cpu_hz), "=d" (edx) + :"r" (fast_gettimeoffset_quotient), + "0" (eax), "1" (edx)); + printk("Detected %ld Hz processor.\n", cpu_hz); + } } -#endif setup_x86_irq(0, &irq0); } diff -u --recursive --new-file v2.1.125/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.1.125/linux/arch/ppc/kernel/pmac_setup.c Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/kernel/pmac_setup.c Wed Oct 14 11:43:13 1998 @@ -145,6 +145,12 @@ #include "../../../drivers/scsi/sd.h" #include "../../../drivers/scsi/hosts.h" +#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) +#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) +#define SD_MINOR_NUMBER(i) ((i) & 255) +#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), SD_MINOR_NUMBER(i)) +#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4) + kdev_t sd_find_target(void *host, int tgt) { Scsi_Disk *dp; @@ -153,7 +159,7 @@ for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) if (dp->device != NULL && dp->device->host == host && dp->device->id == tgt) - return MKDEV(SCSI_DISK_MAJOR, i << 4); + return MKDEV_SD(i); return 0; } #endif diff -u --recursive --new-file v2.1.125/linux/arch/ppc/kernel/pmac_setup.c.orig linux/arch/ppc/kernel/pmac_setup.c.orig --- v2.1.125/linux/arch/ppc/kernel/pmac_setup.c.orig Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/pmac_setup.c.orig Wed Sep 30 10:14:17 1998 @@ -0,0 +1,382 @@ +/* + * linux/arch/ppc/kernel/setup.c + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Adapted for Power Macintosh by Paul Mackerras + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * + * Derived from "arch/alpha/kernel/setup.c" + * Copyright (C) 1995 Linus Torvalds + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +/* + * bootup setup stuff.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "time.h" + +unsigned char drive_info; + +extern char saved_command_line[]; + +#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */ + +extern void zs_kgdb_hook(int tty_num); +static void ohare_init(void); + +__pmac + +int +pmac_get_cpuinfo(char *buffer) +{ + int len; + struct device_node *np; + char *pp; + int plen; + + /* find motherboard type */ + len = sprintf(buffer, "machine\t\t: "); + np = find_devices("device-tree"); + if (np != NULL) { + pp = (char *) get_property(np, "model", NULL); + if (pp != NULL) + len += sprintf(buffer+len, "%s\n", pp); + else + len += sprintf(buffer+len, "PowerMac\n"); + pp = (char *) get_property(np, "compatible", &plen); + if (pp != NULL) { + len += sprintf(buffer+len, "motherboard\t:"); + while (plen > 0) { + int l = strlen(pp) + 1; + len += sprintf(buffer+len, " %s", pp); + plen -= l; + pp += l; + } + buffer[len++] = '\n'; + } + } else + len += sprintf(buffer+len, "PowerMac\n"); + + /* find l2 cache info */ + np = find_devices("l2-cache"); + if (np == 0) + np = find_type_devices("cache"); + if (np != 0) { + unsigned int *ic = (unsigned int *) + get_property(np, "i-cache-size", NULL); + unsigned int *dc = (unsigned int *) + get_property(np, "d-cache-size", NULL); + len += sprintf(buffer+len, "L2 cache\t:"); + if (get_property(np, "cache-unified", NULL) != 0 && dc) { + len += sprintf(buffer+len, " %dK unified", *dc / 1024); + } else { + if (ic) + len += sprintf(buffer+len, " %dK instruction", + *ic / 1024); + if (dc) + len += sprintf(buffer+len, "%s %dK data", + (ic? " +": ""), *dc / 1024); + } + pp = get_property(np, "ram-type", NULL); + if (pp) + len += sprintf(buffer+len, " %s", pp); + buffer[len++] = '\n'; + } + + /* find ram info */ + np = find_devices("memory"); + if (np != 0) { + struct reg_property *reg = (struct reg_property *) + get_property(np, "reg", NULL); + if (reg != 0) { + len += sprintf(buffer+len, "memory\t\t: %dMB\n", + reg->size >> 20); + } + } + + return len; +} + +#ifdef CONFIG_SCSI +/* Find the device number for the disk (if any) at target tgt + on host adaptor host. + XXX this really really should be in drivers/scsi/sd.c. */ +#include +#include "../../../drivers/scsi/scsi.h" +#include "../../../drivers/scsi/sd.h" +#include "../../../drivers/scsi/hosts.h" + +kdev_t sd_find_target(void *host, int tgt) +{ + Scsi_Disk *dp; + int i; + + for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp) + if (dp->device != NULL && dp->device->host == host + && dp->device->id == tgt) + return MKDEV(SCSI_DISK_MAJOR, i << 4); + return 0; +} +#endif + +/* + * Dummy mksound function that does nothing. + * The real one is in the dmasound driver. + */ +static void +pmac_mksound(unsigned int hz, unsigned int ticks) +{ +} + +static volatile u32 *sysctrl_regs; +static volatile u32 *feature_addr; + +__initfunc(void +pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) +{ + struct device_node *cpu; + int *fp; + + /* Set loops_per_sec to a half-way reasonable value, + for use until calibrate_delay gets called. */ + cpu = find_type_devices("cpu"); + if (cpu != 0) { + fp = (int *) get_property(cpu, "clock-frequency", NULL); + if (fp != 0) { + switch (_get_PVR() >> 16) { + case 4: /* 604 */ + case 9: /* 604e */ + case 10: /* mach V (604ev5) */ + case 20: /* 620 */ + loops_per_sec = *fp; + break; + default: /* 601, 603, etc. */ + loops_per_sec = *fp / 2; + } + } else + loops_per_sec = 50000000; + } + + /* this area has the CPU identification register + and some registers used by smp boards */ + sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); + __ioremap(0xffc00000, 0x400000, pgprot_val(PAGE_READONLY)); + + *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); + + ohare_init(); + +#ifdef CONFIG_KGDB + zs_kgdb_hook(0); +#endif + + find_via_cuda(); + find_via_pmu(); + +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#endif + + kd_mksound = pmac_mksound; + +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start) + ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0); + else +#endif + ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE); +} + +__initfunc(static void ohare_init(void)) +{ + struct device_node *np; + + np = find_devices("ohare"); + if (np == 0) + return; + if (np->next != 0) + printk(KERN_WARNING "only using the first ohare\n"); + if (np->n_addrs == 0) { + printk(KERN_ERR "No addresses for %s\n", np->full_name); + return; + } + feature_addr = (volatile u32 *) + ioremap(np->addrs[0].address + OHARE_FEATURE_REG, 4); + + if (find_devices("via-pmu") == 0) { + printk(KERN_INFO "Twiddling the magic ohare bits\n"); + out_le32(feature_addr, STARMAX_FEATURES); + } else { + out_le32(feature_addr, in_le32(feature_addr) | PBOOK_FEATURES); + printk(KERN_DEBUG "feature reg = %x\n", in_le32(feature_addr)); + } + + /* + * Turn on the L2 cache. + * We assume that we have a PSX memory controller iff + * we have an ohare I/O controller. + */ + if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { + if (sysctrl_regs[4] & 0x10) + sysctrl_regs[4] |= 0x04000020; + else + sysctrl_regs[4] |= 0x04000000; + printk(KERN_INFO "Level 2 cache enabled\n"); + } +} + +extern char *bootpath; +extern char *bootdevice; +void *boot_host; +int boot_target; +int boot_part; +kdev_t boot_dev; + +__initfunc(void powermac_init(void)) +{ + adb_init(); + pmac_nvram_init(); + if (_machine == _MACH_Pmac) { + media_bay_init(); + } +} + +#ifdef CONFIG_SCSI +__initfunc(void +note_scsi_host(struct device_node *node, void *host)) +{ + int l; + char *p; + + l = strlen(node->full_name); + if (bootpath != NULL && bootdevice != NULL + && strncmp(node->full_name, bootdevice, l) == 0 + && (bootdevice[l] == '/' || bootdevice[l] == 0)) { + boot_host = host; + /* + * There's a bug in OF 1.0.5. (Why am I not surprised.) + * If you pass a path like scsi/sd@1:0 to canon, it returns + * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0 + * That is, the scsi target number doesn't get preserved. + * So we pick the target number out of bootpath and use that. + */ + p = strstr(bootpath, "/sd@"); + if (p != NULL) { + p += 4; + boot_target = simple_strtoul(p, NULL, 10); + p = strchr(p, ':'); + if (p != NULL) + boot_part = simple_strtoul(p + 1, NULL, 10); + } + } +} +#endif + +#ifdef CONFIG_BLK_DEV_IDE_PMAC +extern int pmac_ide_count; +extern struct device_node *pmac_ide_node[]; +static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; + +__initfunc(kdev_t find_ide_boot(void)) +{ + char *p; + int i, n; + + if (bootdevice == NULL) + return 0; + p = strrchr(bootdevice, '/'); + if (p == NULL) + return 0; + n = p - bootdevice; + + /* + * Look through the list of IDE interfaces for this one. + */ + for (i = 0; i < pmac_ide_count; ++i) { + char *name = pmac_ide_node[i]->full_name; + if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) { + /* XXX should cope with the 2nd drive as well... */ + return MKDEV(ide_majors[i], 0); + } + } + + return 0; +} +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ + +__initfunc(void find_boot_device(void)) +{ +#ifdef CONFIG_SCSI + if (boot_host != NULL) { + boot_dev = sd_find_target(boot_host, boot_target); + if (boot_dev != 0) + return; + } +#endif +#ifdef CONFIG_BLK_DEV_IDE_PMAC + boot_dev = find_ide_boot(); +#endif +} + +__initfunc(void note_bootable_part(kdev_t dev, int part)) +{ + static int found_boot = 0; + char *p; + + /* Do nothing if the root has been set already. */ + if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)) + return; + p = strstr(saved_command_line, "root="); + if (p != NULL && (p == saved_command_line || p[-1] == ' ')) + return; + + if (!found_boot) { + find_boot_device(); + found_boot = 1; + } + if (dev == boot_dev) { + ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part); + boot_dev = NODEV; + printk(" (root)"); + } +} + diff -u --recursive --new-file v2.1.125/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.1.125/linux/drivers/block/Config.in Mon Oct 5 13:13:38 1998 +++ linux/drivers/block/Config.in Mon Oct 12 11:40:12 1998 @@ -43,6 +43,7 @@ bool ' Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 bool ' NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415 bool ' VIA82C586 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_VIA82C586 + bool ' CMD646 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_CMD646 fi fi fi diff -u --recursive --new-file v2.1.125/linux/drivers/block/README.fd linux/drivers/block/README.fd --- v2.1.125/linux/drivers/block/README.fd Wed Jun 24 22:54:04 1998 +++ linux/drivers/block/README.fd Mon Oct 12 14:13:54 1998 @@ -102,12 +102,12 @@ Tells the floppy driver that a workable DMA channel is available (the default). -floppy=nofifo + floppy=nofifo Disables the FIFO entirely. This is needed if you get "Bus master arbitration error" messages from your Ethernet card (or from other devices) while accessing the floppy. -floppy=fifo + floppy=fifo Enables the FIFO (default) floppy=,fifo_depth @@ -188,6 +188,13 @@ floppy=,dma Sets the floppy DMA channel to instead of 2 + + floppy=slow + Use PS/2 stepping rate: + " PS/2 floppies have much slower step rates than regular floppies. + It's been recommended that take about 1/4 of the default speed + in some more extreme cases." + Supporting utilities and additional documentation: diff -u --recursive --new-file v2.1.125/linux/drivers/block/acsi.c linux/drivers/block/acsi.c --- v2.1.125/linux/drivers/block/acsi.c Wed Aug 26 11:37:34 1998 +++ linux/drivers/block/acsi.c Fri Oct 9 11:56:59 1998 @@ -3,7 +3,7 @@ * * Copyright 1994 Roman Hodek * - * Some parts are based on hd.c by Linus Thorvalds + * Some parts are based on hd.c by Linus Torvalds * * 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 diff -u --recursive --new-file v2.1.125/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.125/linux/drivers/block/floppy.c Mon Oct 5 13:13:38 1998 +++ linux/drivers/block/floppy.c Mon Oct 12 14:13:54 1998 @@ -153,6 +153,11 @@ #include #include +/* + * PS/2 floppies have much slower step rates than regular floppies. + * It's been recommended that take about 1/4 of the default speed + * in some more extreme cases. + */ static int slow_floppy = 0; #include @@ -354,7 +359,7 @@ 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/ {{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0, - 0, { 2, 5, 6,23,10,20,11, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/ + 0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/ {{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0, 0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/ @@ -1051,6 +1056,7 @@ static void setup_DMA(void) { unsigned long flags; + unsigned long f; #ifdef FLOPPY_SANITY_CHECK if (raw_cmd->length == 0){ @@ -1072,17 +1078,20 @@ } #endif INT_OFF; + f=claim_dma_lock(); fd_disable_dma(); #ifdef fd_dma_setup if(fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length, (raw_cmd->flags & FD_RAW_READ)? DMA_MODE_READ : DMA_MODE_WRITE, FDCS->address) < 0) { + release_dma_lock(f); INT_ON; cont->done(0); FDCS->reset=1; return; } + release_dma_lock(f); #else fd_clear_dma_ff(); fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length); @@ -1092,6 +1101,7 @@ fd_set_dma_count(raw_cmd->length); virtual_dma_port = FDCS->address; fd_enable_dma(); + release_dma_lock(f); #endif INT_ON; floppy_disable_hlt(); @@ -1694,11 +1704,15 @@ { void (*handler)(void) = DEVICE_INTR; int do_print; + unsigned long f; lasthandler = handler; interruptjiffies = jiffies; + f=claim_dma_lock(); fd_disable_dma(); + release_dma_lock(f); + floppy_enable_hlt(); CLEAR_INTR; if (fdc >= N_FDC || FDCS->address == -1){ @@ -1779,13 +1793,18 @@ */ static void reset_fdc(void) { + unsigned long flags; + SET_INTR(reset_interrupt); FDCS->reset = 0; reset_fdc_info(0); /* Pseudo-DMA may intercept 'reset finished' interrupt. */ /* Irrelevant for systems with true DMA (i386). */ + + flags=claim_dma_lock(); fd_disable_dma(); + release_dma_lock(flags); if (FDCS->version >= FDC_82072A) fd_outb(0x80 | (FDCS->dtr &3), FD_STATUS); @@ -1844,12 +1863,18 @@ static void floppy_shutdown(void) { + unsigned long flags; + if (!initialising) show_floppy(); cancel_activity(); floppy_enable_hlt(); + + flags=claim_dma_lock(); fd_disable_dma(); + release_dma_lock(flags); + /* avoid dma going to a random drive after shutdown */ if (!initialising) @@ -1897,6 +1922,8 @@ static void floppy_ready(void) { + unsigned long flags; + CHECK_RESET; if (start_motor(floppy_ready)) return; if (fdc_dtr()) return; @@ -1915,8 +1942,12 @@ #ifdef fd_chose_dma_mode if ((raw_cmd->flags & FD_RAW_READ) || (raw_cmd->flags & FD_RAW_WRITE)) + { + flags=claim_dma_lock(); fd_chose_dma_mode(raw_cmd->kernel_data, raw_cmd->length); + release_dma_lock(flags); + } #endif if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){ @@ -3020,7 +3051,12 @@ raw_cmd->reply[i] = reply_buffer[i]; if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) + { + unsigned long flags; + flags=claim_dma_lock(); raw_cmd->length = fd_get_dma_residue(); + release_dma_lock(flags); + } if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) && (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0))) @@ -4025,6 +4061,7 @@ { "usefifo", 0, &no_fifo, 0, 0 }, { "cmos", set_cmos, 0, 0, 0 }, + { "slow", 0, &slow_floppy, 1, 0 }, { "unexpected_interrupts", 0, &print_unex, 1, 0 }, { "no_unexpected_interrupts", 0, &print_unex, 0, 0 }, @@ -4036,15 +4073,6 @@ int i; int param; if (str) { - /* - * PS/2 floppies have much slower step rates than regular floppies. - * It's been recommended that take about 1/4 of the default speed - * in some more extreme cases. - */ - if( strcmp(str,"slow") == 0) { - slow_floppy = 1; - return; - } for (i=0; i< ARRAY_SIZE(config_params); i++){ if (strcmp(str,config_params[i].name) == 0){ if (ints[0]) @@ -4125,6 +4153,8 @@ #endif if (floppy_grab_irq_and_dma()){ + del_timer(&fd_timeout); + blk_dev[MAJOR_NR].request_fn = NULL; unregister_blkdev(MAJOR_NR,"fd"); del_timer(&fd_timeout); return -EBUSY; @@ -4176,7 +4206,8 @@ current_drive = 0; floppy_release_irq_and_dma(); initialising=0; - if (have_no_fdc) { + if (have_no_fdc) + { DPRINT("no floppy controllers found\n"); unregister_blkdev(MAJOR_NR,"fd"); } diff -u --recursive --new-file v2.1.125/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.1.125/linux/drivers/block/genhd.c Mon Sep 28 10:51:33 1998 +++ linux/drivers/block/genhd.c Wed Oct 14 11:43:13 1998 @@ -71,7 +71,7 @@ { unsigned int part; const char *maj = hd->major_name; - char unit = (minor >> hd->minor_shift) + 'a'; + int unit = (minor >> hd->minor_shift) + 'a'; /* * IDE devices use multiple major numbers, but the drives @@ -91,8 +91,19 @@ unit += 2; case IDE0_MAJOR: maj = "hd"; + break; } part = minor & ((1 << hd->minor_shift) - 1); + if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) { + unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16; + if (unit > 'z') { + unit -= 'z' + 1; + sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26); + if (part) + sprintf(buf + 4, "%d", part); + return buf; + } + } if (part) sprintf(buf, "%s%c%d", maj, unit, part); else diff -u --recursive --new-file v2.1.125/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.1.125/linux/drivers/block/ide-dma.c Thu Sep 17 17:53:35 1998 +++ linux/drivers/block/ide-dma.c Mon Oct 12 11:42:59 1998 @@ -344,6 +344,21 @@ } } +/* + * Needed for allowing full modular support of ide-driver + */ +int ide_release_dma (ide_hwif_t *hwif) +{ + if (hwif->dmatable) { + clear_page((unsigned long)hwif->dmatable); /* clear PRD 1st */ + free_page((unsigned long)hwif->dmatable); /* free PRD 2nd */ + } + if ((hwif->dma_extra) && (hwif->channel == 0)) + release_region((hwif->dma_base + 16), hwif->dma_extra); + release_region(hwif->dma_base, 8); + return 1; +} + __initfunc(void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports)) { static unsigned long dmatable = 0; @@ -404,6 +419,7 @@ if (extra) /* PDC20246 & HPT343 */ request_region(dma_base+16, extra, name); dma_base += hwif->channel ? 8 : 0; + hwif->dma_extra = extra; if (inb(dma_base+2) & 0x80) { printk("%s: simplex device: DMA disabled\n", name); dma_base = 0; diff -u --recursive --new-file v2.1.125/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.1.125/linux/drivers/block/ide-floppy.c Thu Sep 17 17:53:35 1998 +++ linux/drivers/block/ide-floppy.c Wed Oct 14 20:24:55 1998 @@ -868,7 +868,7 @@ if (status.b.check || test_bit (PC_DMA_ERROR, &pc->flags)) { /* Error detected */ #if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: %s: I/O error, ",drive->name); + printk (KERN_INFO "ide-floppy: %s: I/O error\n",drive->name); #endif /* IDEFLOPPY_DEBUG_LOG */ rq->errors++; if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { @@ -1057,6 +1057,7 @@ pc->c[0] = IDEFLOPPY_READ_CAPACITY_CMD; pc->c[7] = 255; pc->c[8] = 255; + pc->request_transfer = 255; } /* diff -u --recursive --new-file v2.1.125/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c --- v2.1.125/linux/drivers/block/ide-pci.c Mon Oct 5 13:13:38 1998 +++ linux/drivers/block/ide-pci.c Mon Oct 12 11:42:59 1998 @@ -117,16 +117,6 @@ unsigned int extra; } ide_pci_device_t; -#ifdef CONFIG_BLK_DEV_OFFBOARD -# define ON_BOARD 0 -# define OFF_BOARD 1 -# define NEVER_BOARD 0 -#else /* CONFIG_BLK_DEV_OFFBOARD */ -# define ON_BOARD 1 -# define OFF_BOARD 0 -# define NEVER_BOARD 0 -#endif /* CONFIG_BLK_DEV_OFFBOARD */ - static ide_pci_device_t ide_pci_chipsets[] __initdata = { {DEVID_PIIXa, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, {DEVID_PIIXb, "PIIX", NULL, {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, ON_BOARD, 0 }, diff -u --recursive --new-file v2.1.125/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.125/linux/drivers/block/ide.c Fri Oct 9 13:27:07 1998 +++ linux/drivers/block/ide.c Mon Oct 12 11:42:59 1998 @@ -1737,6 +1737,11 @@ else hwgroup->hwif = HWIF(hwgroup->drive); +#ifdef CONFIG_BLK_DEV_IDEDMA + if (hwif->dma_base) + (void) ide_release_dma(hwif); +#endif /* CONFIG_BLK_DEV_IDEDMA */ + /* * Remove us from the kernel's knowledge */ @@ -2998,8 +3003,13 @@ { int index; - for (index = 0; index < MAX_HWIFS; ++index) + for (index = 0; index < MAX_HWIFS; ++index) { ide_unregister(index); +#ifdef CONFIG_BLK_DEV_IDEDMA + if (ide_hwifs[index].dma_base) + (void) ide_release_dma(&ide_hwifs[index]); +#endif /* CONFIG_BLK_DEV_IDEDMA */ + } #ifdef CONFIG_PROC_FS proc_ide_destroy(); #endif diff -u --recursive --new-file v2.1.125/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v2.1.125/linux/drivers/block/ide.h Fri Oct 9 13:27:07 1998 +++ linux/drivers/block/ide.h Fri Oct 16 15:41:59 1998 @@ -328,6 +328,7 @@ unsigned long *dmatable; /* dma physical region descriptor table */ struct hwif_s *mate; /* other hwif from same PCI chip */ unsigned long dma_base; /* base addr for dma ports */ + unsigned dma_extra; /* extra addr for dma ports */ unsigned long config_data; /* for use by chipset-specific code */ unsigned long select_data; /* for use by chipset-specific code */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ @@ -725,6 +726,14 @@ int ide_replace_subdriver(ide_drive_t *drive, const char *driver); #ifdef CONFIG_BLK_DEV_IDEPCI +#define ON_BOARD 1 +#define NEVER_BOARD 0 +#ifdef CONFIG_BLK_DEV_OFFBOARD +# define OFF_BOARD ON_BOARD +#else /* CONFIG_BLK_DEV_OFFBOARD */ +# define OFF_BOARD NEVER_BOARD +#endif /* CONFIG_BLK_DEV_OFFBOARD */ + unsigned long ide_find_free_region (unsigned short size) __init; void ide_scan_pcibus (void) __init; #endif @@ -735,6 +744,7 @@ void ide_dma_intr (ide_drive_t *drive); int check_drive_lists (ide_drive_t *drive, int good_bad); int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive); +int ide_release_dma (ide_hwif_t *hwif); void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init; unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init; #endif diff -u --recursive --new-file v2.1.125/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.1.125/linux/drivers/block/ll_rw_blk.c Mon Aug 3 12:45:44 1998 +++ linux/drivers/block/ll_rw_blk.c Wed Oct 14 11:43:13 1998 @@ -93,8 +93,8 @@ * then 512 bytes is assumed. * else * sector_size is hardsect_size[MAJOR][MINOR] - * This is currently set by some scsi device and read by the msdos fs driver - * This might be a some uses later. + * This is currently set by some scsi devices and read by the msdos fs driver. + * Other uses may appear later. */ int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, }; @@ -297,8 +297,8 @@ int queue_new_request = 0; switch (MAJOR(req->rq_dev)) { - case SCSI_DISK_MAJOR: - disk_index = (MINOR(req->rq_dev) & 0x0070) >> 4; + case SCSI_DISK0_MAJOR: + disk_index = (MINOR(req->rq_dev) & 0x00f0) >> 4; if (disk_index < 4) drive_stat_acct(req->cmd, req->nr_sectors, disk_index); break; @@ -479,7 +479,14 @@ break; /* fall through */ - case SCSI_DISK_MAJOR: + case SCSI_DISK0_MAJOR: + case SCSI_DISK1_MAJOR: + case SCSI_DISK2_MAJOR: + case SCSI_DISK3_MAJOR: + case SCSI_DISK4_MAJOR: + case SCSI_DISK5_MAJOR: + case SCSI_DISK6_MAJOR: + case SCSI_DISK7_MAJOR: case SCSI_CDROM_MAJOR: do { diff -u --recursive --new-file v2.1.125/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.1.125/linux/drivers/block/xd.c Wed Aug 26 11:37:35 1998 +++ linux/drivers/block/xd.c Fri Oct 9 11:56:59 1998 @@ -533,6 +533,8 @@ /* xd_setup_dma: set up the DMA controller for a data transfer */ static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count) { + unsigned long f; + if (nodma) return (PIO_MODE); if (((u_int) buffer & 0xFFFF0000) != (((u_int) buffer + count) & 0xFFFF0000)) { @@ -541,11 +543,15 @@ #endif /* DEBUG_OTHER */ return (PIO_MODE); } + + f=claim_dma_lock(); disable_dma(xd_dma); clear_dma_ff(xd_dma); set_dma_mode(xd_dma,mode); set_dma_addr(xd_dma,(u_int) buffer); set_dma_count(xd_dma,count); + + release_dma_lock(f); return (DMA_MODE); /* use DMA and INT */ } @@ -597,13 +603,22 @@ static inline u_int xd_wait_for_IRQ (void) { + unsigned long flags; xd_watchdog_int.expires = jiffies + 8 * HZ; add_timer(&xd_watchdog_int); + + flags=claim_dma_lock(); enable_dma(xd_dma); + release_dma_lock(flags); + sleep_on(&xd_wait_int); del_timer(&xd_watchdog_int); xdc_busy = 0; + + flags=claim_dma_lock(); disable_dma(xd_dma); + release_dma_lock(flags); + if (xd_error) { printk("xd: missed IRQ - command aborted\n"); xd_error = 0; diff -u --recursive --new-file v2.1.125/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c --- v2.1.125/linux/drivers/cdrom/cdu31a.c Thu Sep 17 17:53:35 1998 +++ linux/drivers/cdrom/cdu31a.c Wed Oct 14 11:37:27 1998 @@ -3022,7 +3022,9 @@ { return -EIO; } - + + copy_from_user(&ra, (char *) arg, sizeof(ra)); + if (ra.nframes == 0) { return 0; @@ -3031,7 +3033,6 @@ i=verify_area(VERIFY_WRITE, ra.buf, CD_FRAMESIZE_RAW * ra.nframes); if(i<0) return i; - copy_from_user(&ra, (char *) arg, sizeof(ra)); if (ra.addr_format == CDROM_LBA) { diff -u --recursive --new-file v2.1.125/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.1.125/linux/drivers/char/Config.in Fri Oct 9 13:27:07 1998 +++ linux/drivers/char/Config.in Fri Oct 9 11:44:19 1998 @@ -56,7 +56,7 @@ tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE tristate 'Logitech busmouse support' CONFIG_BUSMOUSE tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE - tristate 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE + bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE tristate 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE tristate 'PC110 digitizer pad support' CONFIG_PC110_PAD fi diff -u --recursive --new-file v2.1.125/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.125/linux/drivers/char/Makefile Fri Oct 9 13:27:07 1998 +++ linux/drivers/char/Makefile Fri Oct 9 11:44:19 1998 @@ -184,14 +184,6 @@ endif endif -ifeq ($(CONFIG_PSMOUSE),y) -L_OBJS += psaux.o -else - ifeq ($(CONFIG_PSMOUSE),m) - M_OBJS += psaux.o - endif -endif - ifeq ($(CONFIG_SOFT_WATCHDOG),y) L_OBJS += softdog.o else diff -u --recursive --new-file v2.1.125/linux/drivers/char/bttv.c linux/drivers/char/bttv.c --- v2.1.125/linux/drivers/char/bttv.c Thu Sep 17 17:53:36 1998 +++ linux/drivers/char/bttv.c Fri Oct 9 12:16:43 1998 @@ -85,7 +85,7 @@ static unsigned int radio[BTTV_MAX]; static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 }; -static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0 }; +static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0 }; static int bttv_num; /* number of Bt848s in use */ static struct bttv bttvs[BTTV_MAX]; @@ -96,8 +96,6 @@ { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } #define I2C_GET() (btread(BT848_I2C)&1) -#define AUDIO_MUTE_DELAY 10000 -#define FREQ_CHANGE_DELAY 20000 #define EEPROM_WRITE_DELAY 20000 /*******************************/ @@ -433,9 +431,9 @@ {0, 0xc00, 0x800, 0x400, 0xc00, 0}}, /* TurboTV */ { 3, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}}, - /* Newer Hauppauge */ + /* Newer Hauppauge */ { 2, 0, 2, 1, { 2, 0, 0, 0}, {0, 1, 2, 3, 4}}, - + }; #define TVCARDS (sizeof(tvcards)/sizeof(tvcard)) @@ -585,7 +583,7 @@ else { btwrite(0x08,BT848_TGCTRL); - btv->pll.pll_crystal|=2; + btv->pll.pll_crystal|=2; return 1; } udelay(10000); @@ -623,8 +621,9 @@ #define VBIBUF_SIZE 65536 -/* Maximum sample number per VBI line is 2044, can NTSC deliver this? +/* Maximum sample number per VBI line is 2044, NTSC delivers 1600 Note that we write 2048-aligned to keep alignment to memory pages + VBI_RISC is written so that it applies to either 2044 or 1600 */ #define VBI_SPL 2044 @@ -783,199 +782,102 @@ return 0; } -/* does this really make a difference ???? */ -#define BURST_MAX 4096 - -static inline void write_risc_segment(unsigned int **rp, unsigned long line_adr, unsigned int command, - int *x, uint dx, uint bpp, uint width) +static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int h) { - unsigned int flags, len; - - if (!dx) - return; - len=dx*bpp; - -#ifdef LIMIT_DMA - if (command==BT848_RISC_WRITEC) - { - unsigned int dx2=BURST_MAX/bpp; - while (len>BURST_MAX) - { - write_risc_segment(rp, line_adr, command, - &x,dx2, bpp, width); - dx-=dx2; - len=dx*bpp; - } - } -#endif - - /* mask upper 8 bits for 24+8 bit overlay modes */ - flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0); - - if (*x==0) - { - if (command==BT848_RISC_SKIP) - { - if (dx>3)] |= (1<<(j&7)); } static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) { - int i,t; - int yy, y, x, dx; - struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2; - int bpp, bpl, width, height, inter; - unsigned int **rp,*ro,*re; + int i, line, x, y, bpl, width, height, inter; + unsigned int bpp, dx, sx, **rp, *ro, *re, flags, len; unsigned long adr; - int cx,cx2,cy,cy2; + unsigned char *clipmap, cbit, lastbit, outofmem; inter=(btv->win.interlace&1)^1; bpp=btv->win.bpp; + if (bpp==15) /* handle 15bpp as 16bpp in calculations */ + bpp++; bpl=btv->win.bpl; ro=btv->risc_odd; re=btv->risc_even; - width=btv->win.width; - height=btv->win.height; + if((width=btv->win.width)>1023) + width = 1023; /* sanity check */ + if((height=btv->win.height)>625) + height = 625; /* sanity check */ adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; - - /* clip clipping rects against viewing window AND screen + if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { + /* can't clip, don't generate any risc code */ + *(ro++)=BT848_RISC_JUMP; + *(ro++)=btv->bus_vbi_even; + *(re++)=BT848_RISC_JUMP; + *(re++)=btv->bus_vbi_odd; + } + if (ncr < 0) { /* bitmap was pased */ + memcpy(clipmap, (unsigned char *)cr, VIDEO_CLIPMAP_SIZE); + } else { /* convert rectangular clips to a bitmap */ + memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */ + for (i=0; iwin.x<0) ? (-btv->win.x) : 0; - cy=(btv->win.y<0) ? (-btv->win.y) : 0; - cx2=(btv->win.x+width>btv->win.swidth) ? - (btv->win.swidth-btv->win.x) : width; - cy2=(btv->win.y+height>btv->win.sheight) ? - (btv->win.sheight-btv->win.y) : height; - first.next=NULL; - for (i=0; i0) - { - if (cr[i].height<=t) - continue; - cr[i].height-=t; - cr[i].y=cy; - } - if ((t=cy2-cr[i].y)0) - { - if (cr[i].width<=t) - continue; - cr[i].width-=t; - cr[i].x=cx; - } - if ((t=cx2-cr[i].x)next) && (cr[i].y > cur->next->y)) - cur=nx; - cur->next=&(cr[i]); - cr[i].next=nx; - } - first2.next=NULL; + clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ? + (btv->win.swidth-btv->win.x) : width, 0, 1024, 768); + clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? + (btv->win.sheight-btv->win.y) : height,1024,768); + if (btv->win.x<0) + clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); + if (btv->win.y<0) + clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); *(ro++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(ro++)=0; *(re++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(re++)=0; - /* loop through all lines */ - for (yy=0; yy<(height<>inter; - rp= (yy&1) ? &re : &ro; - - /* remove rects with y2 > y */ - if ((cur=first2.next)) - { - prev=&first2; - do - { - if (cur->y+cur->height <= y) - prev->next=cur->next; - else - prev=cur; - } - while ((cur=cur->next)); - } - - /* add rect to second (x-sorted) list if rect.y == y */ - if ((cur=first.next)) - { - while ((cur) && (cur->y == y)) - { - first.next=cur->next; - cur2=&first2; - while ((nx2=cur2->next) && (cur->x > cur2->next->x)) - cur2=nx2; - cur2->next=cur; - cur->next=nx2; - cur=first.next; - } - } - x=0; - if ((btv->win.y+y<=0)||(btv->win.y+y>=btv->win.sheight)) - write_risc_segment(rp, adr, BT848_RISC_SKIP, &x, - width, bpp, width); - else - { - dx=cx; - for (cur2=first2.next; cur2; cur2=cur2->next) - { - if (x+dx < cur2->x) - { - write_risc_segment(rp, adr, BT848_RISC_SKIP, - &x, dx, bpp, width); - dx=cur2->x-x; - write_risc_segment(rp, adr, BT848_RISC_WRITEC, - &x, dx, bpp, width); - dx=cur2->width; - } - else if (x+dx < cur2->x+cur2->width) - dx=cur2->x+cur2->width-x; - } - if (cx2>inter; + rp= (line&1) ? &re : &ro; + lastbit=(clipmap[y<<7]&1); + for(x=dx=1,sx=0; x<=width && !outofmem; x++) { + cbit = (clipmap[(y<<7)+(x>>3)] & (1<<(x&7))); + if (x < width && !lastbit == !cbit) + dx++; + else { /* generate the dma controller code */ + len = dx * bpp; + flags = ((bpp==4) ? BT848_RISC_BYTE3 : 0); + flags |= ((!sx) ? BT848_RISC_SOL : 0); + flags |= ((sx + dx == width) ? BT848_RISC_EOL : 0); + if (!lastbit) { + *((*rp)++)=BT848_RISC_WRITE|flags|len; + *((*rp)++)=adr + bpp * sx; + } else + *((*rp)++)=BT848_RISC_SKIP|flags|len; + lastbit=cbit; + sx += dx; + dx = 1; + if (ro - btv->risc_odd > RISCMEM_LEN/2 - 16) + outofmem++; + if (re - btv->risc_even > RISCMEM_LEN/2 - 16) + outofmem++; + } + } + if ((!inter)||(line&1)) adr+=bpl; } - - *(ro++)=BT848_RISC_JUMP; + vfree(clipmap); + /* outofmem flag relies on the following code to discard extra data */ + *(ro++)=BT848_RISC_JUMP; *(ro++)=btv->bus_vbi_even; *(re++)=BT848_RISC_JUMP; *(re++)=btv->bus_vbi_odd; @@ -1005,38 +907,39 @@ static struct tvnorm tvnorms[] = { /* PAL-BDGHI */ /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ + /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */ { 35468950, 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - 1135, 186, 924, 0x20}, + 1135, 178, 924, 0x20}, /* { 35468950, 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - 944, 186, 922, 0x20}, + 944, 178, 922, 0x20}, */ /* NTSC */ { 28636363, 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), - 780, 135, 754, 0x1a}, - /* SECAM */ - { 28636363, - 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0), - 780, 135, 754, 0x16}, + 780, 122, 754, 0x1a}, + /* SECAM - phase means nothing in SECAM, bdelay is useless */ + { 35468950, + 924, 576,1135, 0x7f, 0x72, (BT848_IFORM_SECAM|BT848_IFORM_XT1), + 1135, 178, 924, 0x20}, /* PAL-M */ { 28636363, 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_PAL_M|BT848_IFORM_XT0), - 780, 135, 754, 0x16}, + 780, 122, 754, 0x1a}, /* PAL-N */ { 35468950, 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_N|BT848_IFORM_XT1), - 944, 186, 922, 0x20}, + 944, 178, 922, 0x20}, /* PAL-NC */ { 35468950, 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_NC|BT848_IFORM_XT0), - 944, 186, 922, 0x20}, + 944, 178, 922, 0x20}, /* NTSC-Japan */ { 28636363, 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC_J|BT848_IFORM_XT0), - 780, 135, 754, 0x16}, + 780, 122, 754, 0x1a}, }; #define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm)) @@ -1146,6 +1049,12 @@ { unsigned short format; + /* setup proper VBI capture length for given video mode */ + if (btv->win.norm == VIDEO_MODE_NTSC) + btwrite(144, BT848_VBI_PACK_SIZE); /* 1600 samples */ + else + btwrite(255, BT848_VBI_PACK_SIZE); /* 2044 samples */ + btwrite(1, BT848_VBI_PACK_DEL); /* bit 9 for above */ btv->win.color_fmt = format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : bpp2fmt[(btv->win.bpp-1)&3]; @@ -1172,11 +1081,7 @@ static void set_freq(struct bttv *btv, unsigned short freq) { int fixme = freq; /* XXX */ - int oldAudio = btv->audio; - audio(btv, AUDIO_MUTE); - udelay(AUDIO_MUTE_DELAY); - if (btv->radio) { if (btv->have_tuner) @@ -1204,10 +1109,6 @@ } } - if (!(oldAudio & AUDIO_MUTE)) { - udelay(FREQ_CHANGE_DELAY); - audio(btv, AUDIO_UNMUTE); - } } @@ -1604,15 +1505,20 @@ case VIDIOCSWIN: { struct video_window vw; - struct video_clip *vcp; + struct video_clip *vcp = NULL; int on; if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; - if(vw.flags) + if(vw.flags || vw.width < 16 || vw.height < 16) { + bt848_cap(btv,0); return -EINVAL; - + } + if (btv->win.bpp < 4) { /* adjust and align writes */ + vw.x = (vw.x + 3) & ~3; + vw.width = (vw.width - 3) & ~3; + } btv->win.x=vw.x; btv->win.y=vw.y; btv->win.width=vw.width; @@ -1623,26 +1529,37 @@ else btv->win.interlace=0; - on=(btv->cap&3)?1:0; + on=(btv->cap&3); bt848_cap(btv,0); bt848_set_winsize(btv); - if(vw.clipcount>256) - return -EDOM; /* Too many! */ - /* * Do any clips. */ - - vcp=vmalloc(sizeof(struct video_clip)*(vw.clipcount+4)); - if(vcp==NULL) - return -ENOMEM; - if(vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) - return -EFAULT; - make_clip_tab(btv,vcp, vw.clipcount); - vfree(vcp); - if(on && btv->win.vidadr!=0) + if(vw.clipcount<0) { + if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) + return -ENOMEM; + if(copy_from_user(vcp, vw.clips, + VIDEO_CLIPMAP_SIZE)) { + vfree(vcp); + return -EFAULT; + } + } else if (vw.clipcount) { + if((vcp=vmalloc(sizeof(struct video_clip)* + (vw.clipcount))) == NULL) + return -ENOMEM; + if(copy_from_user(vcp,vw.clips, + sizeof(struct video_clip)* + vw.clipcount)) { + vfree(vcp); + return -EFAULT; + } + } + make_clip_tab(btv, vcp, vw.clipcount); + if (vw.clipcount != 0) + vfree(vcp); + if(on && btv->win.vidadr != 0) bt848_cap(btv,1); return 0; } @@ -1700,7 +1617,9 @@ return -EPERM; if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; - if(v.depth!=8 && v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32) + if(v.depth!=8 && v.depth!=15 && v.depth!=16 && + v.depth!=24 && v.depth!=32 && v.width > 16 && + v.height > 16 && v.bytesperline > 16) return -EINVAL; btv->win.vidadr=(unsigned long)v.base; btv->win.sheight=v.height; @@ -1801,9 +1720,6 @@ case VIDIOCSYNC: if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT; - if(i>1 || i<0) - return -EINVAL; - switch (btv->frame_stat[i]) { case GBUFFER_UNUSED: return -EINVAL; @@ -1832,24 +1748,25 @@ return -EFAULT; break; - case BTTV_FIELDNR: + case BTTV_FIELDNR: if(copy_to_user((void *) arg, (void *) &btv->last_field, sizeof(btv->last_field))) return -EFAULT; break; - - case BTTV_PLLSET: { - struct bttv_pll_info p; - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) - return -EFAULT; - btv->pll.pll_ifreq = p.pll_ifreq; - btv->pll.pll_ofreq = p.pll_ofreq; - btv->pll.pll_crystal = p.pll_crystal; + case BTTV_PLLSET: + { + struct bttv_pll_info p; + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) + return -EFAULT; + btv->pll.pll_ifreq = p.pll_ifreq; + btv->pll.pll_ofreq = p.pll_ofreq; + btv->pll.pll_crystal = p.pll_crystal; break; - } + } + case VIDIOCMCAPTURE: { struct video_mmap vm; @@ -2418,12 +2335,11 @@ { btv->type=BTTV_MIRO; - if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0) - { + if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0) { if(btv->id>849) btv->type=BTTV_HAUPPAUGE878; else - btv->type=BTTV_HAUPPAUGE; + btv->type=BTTV_HAUPPAUGE; } else if (I2CRead(&(btv->i2c), I2C_STBEE)>=0) @@ -2459,7 +2375,6 @@ /* How do I detect the tuner type for other cards but Miro ??? */ printk(KERN_INFO "bttv%d: model: ", btv->nr); - sprintf(btv->video_dev.name,"BT%d",btv->id); switch (btv->type) { @@ -2472,10 +2387,9 @@ I2C_DRIVERID_TUNER, TUNER_SET_TYPE,&tunertype); } - strcat(btv->video_dev.name, "(Miro)"); + strcat(btv->video_dev.name,"(Miro)"); break; case BTTV_HAUPPAUGE: - case BTTV_HAUPPAUGE878: printk("HAUPPAUGE\n"); strcat(btv->video_dev.name,"(Hauppauge)"); break; @@ -2650,11 +2564,6 @@ /* select direct input */ btwrite(0x00, BT848_GPIO_REG_INP); - - btwrite(0xff, BT848_VBI_PACK_SIZE); - btwrite(1, BT848_VBI_PACK_DEL); - - btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI, BT848_IFORM); @@ -2776,6 +2685,8 @@ if (stat&(1<<28)) { btv->vbip=0; + /* inc vbi frame count for detecting drops */ + (*(u32 *)&(btv->vbibuf[VBIBUF_SIZE - 4]))++; wake_up_interruptible(&btv->vbiq); } @@ -2844,10 +2755,12 @@ } if (astat&BT848_INT_HLOCK) { +#if 0 if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio)) audio(btv, AUDIO_ON); else audio(btv, AUDIO_OFF); +#endif } if (astat&BT848_INT_I2CDONE) @@ -2923,16 +2836,16 @@ printk("irq: %d, ",btv->irq); printk("memory: 0x%08x.\n", btv->bt848_adr); - btv->pll.pll_ifreq=0; - btv->pll.pll_ofreq=0; - btv->pll.pll_crystal=0; + btv->pll.pll_ifreq=0; + btv->pll.pll_ofreq=0; + btv->pll.pll_crystal=0; if(pll[btv->nr]) if (!(btv->id==848 && btv->revision==0x11)) { printk(KERN_INFO "bttv%d: internal PLL, single crystal operation enabled\n",bttv_num); - btv->pll.pll_ofreq=28636363; - btv->pll.pll_ifreq=35468950; - btv->pll.pll_crystal=BT848_IFORM_XT1; + btv->pll.pll_ofreq=28636363; + btv->pll.pll_ifreq=35468950; + btv->pll.pll_crystal=BT848_IFORM_XT1; } btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); @@ -2997,7 +2910,7 @@ dev = dev->next; } if(bttv_num) - printk(KERN_INFO "bttv: %d BT8xx card(s) found.\n", bttv_num); + printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num); return bttv_num; } @@ -3113,4 +3026,3 @@ * tab-width: 8 * End: */ - diff -u --recursive --new-file v2.1.125/linux/drivers/char/bttv.h linux/drivers/char/bttv.h --- v2.1.125/linux/drivers/char/bttv.h Sat Sep 5 16:46:40 1998 +++ linux/drivers/char/bttv.h Fri Oct 9 12:16:43 1998 @@ -31,7 +31,6 @@ #include "bt848.h" #include -#define MAX_CLIPRECS 100 #define MAX_GBUFFERS 2 #define RISCMEM_LEN (32744*2) @@ -56,10 +55,9 @@ ushort depth; }; - struct bttv_pll_info { - unsigned int pll_ifreq; /* PLL input frequency */ - unsigned int pll_ofreq; /* PLL output frequency */ + unsigned int pll_ifreq; /* PLL input frequency */ + unsigned int pll_ofreq; /* PLL output frequency */ unsigned int pll_crystal; /* Crystal used for input */ }; @@ -143,6 +141,7 @@ int i2c_command; int triton1; }; + #endif /*The following should be done in more portable way. It depends on define diff -u --recursive --new-file v2.1.125/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.1.125/linux/drivers/char/bw-qcam.c Tue Aug 18 22:02:03 1998 +++ linux/drivers/char/bw-qcam.c Fri Oct 9 11:56:59 1998 @@ -296,7 +296,7 @@ if (reg != lastreg) count++; lastreg = reg; - mdelay(1); + mdelay(2); } /* Be liberal in what you accept... */ diff -u --recursive --new-file v2.1.125/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.1.125/linux/drivers/char/esp.c Mon Sep 28 10:51:33 1998 +++ linux/drivers/char/esp.c Fri Oct 9 11:56:59 1998 @@ -395,15 +395,20 @@ static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes) { + unsigned long flags; info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; dma_bytes = num_bytes; info->stat_flags |= ESP_STAT_DMA_RX; + + flags=claim_dma_lock(); 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); + release_dma_lock(flags); + serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); } @@ -412,12 +417,17 @@ { struct tty_struct *tty = info->tty; int num_bytes; - + unsigned long flags; + + + flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); info->stat_flags &= ~ESP_STAT_DMA_RX; num_bytes = dma_bytes - get_dma_residue(dma); + release_dma_lock(flags); + info->icount.rx += num_bytes; memcpy(tty->flip.char_buf_ptr, dma_buffer, num_bytes); @@ -534,6 +544,8 @@ static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes) { + unsigned long flags; + dma_bytes = num_bytes; if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) { @@ -564,34 +576,46 @@ } info->stat_flags |= ESP_STAT_DMA_TX; + + flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma, DMA_MODE_WRITE); set_dma_addr(dma, virt_to_bus(dma_buffer)); set_dma_count(dma, dma_bytes); enable_dma(dma); + release_dma_lock(flags); + serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); } static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info) { int num_bytes; + unsigned long flags; + + flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); num_bytes = dma_bytes - get_dma_residue(dma); info->icount.tx += dma_bytes; + release_dma_lock(flags); if (dma_bytes != num_bytes) { dma_bytes -= num_bytes; memmove(dma_buffer, dma_buffer + num_bytes, dma_bytes); + + flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma, DMA_MODE_WRITE); set_dma_addr(dma, virt_to_bus(dma_buffer)); set_dma_count(dma, dma_bytes); enable_dma(dma); + release_dma_lock(flags); + serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); } else { dma_bytes = 0; @@ -1003,7 +1027,7 @@ */ static void shutdown(struct esp_struct * info) { - unsigned long flags; + unsigned long flags, f; if (!(info->flags & ASYNC_INITIALIZED)) return; @@ -1025,8 +1049,11 @@ /* stop a DMA transfer on the port being closed */ if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) { + f=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); + release_dma_lock(f); + dma_bytes = 0; } diff -u --recursive --new-file v2.1.125/linux/drivers/char/hfmodem/main.c linux/drivers/char/hfmodem/main.c --- v2.1.125/linux/drivers/char/hfmodem/main.c Wed Aug 26 11:37:37 1998 +++ linux/drivers/char/hfmodem/main.c Fri Oct 9 12:20:27 1998 @@ -148,14 +148,6 @@ #define SP_PAR 2 #define SP_MIDI 4 -/* ---------------------------------------------------------------------- */ - -static int parptt_preempt(void *handle) -{ - /* we cannot relinquish the port in the middle of an operation */ - return 1; -} - /* --------------------------------------------------------------------- */ static void parptt_wakeup(void *handle) @@ -176,8 +168,8 @@ pp = pp->next; if (!pp) return 0; - if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, parptt_preempt, parptt_wakeup, - NULL, PARPORT_DEV_LURK, dev))) + if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, NULL, parptt_wakeup, + NULL, PARPORT_DEV_EXCL, dev))) return 0; return 1; } diff -u --recursive --new-file v2.1.125/linux/drivers/char/joystick/joy-console.c linux/drivers/char/joystick/joy-console.c --- v2.1.125/linux/drivers/char/joystick/joy-console.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/joystick/joy-console.c Fri Oct 9 12:20:27 1998 @@ -466,7 +466,9 @@ return port; } - info.port = parport_register_device(pp, "joystick (console)", NULL, js_console_wakeup, NULL, 0, NULL); + info.port = parport_register_device(pp, "joystick (console)", NULL, js_console_wakeup, NULL, PARPORT_DEV_EXCL, NULL); + if (!info.port) + return port; info.wanted = 0; info.use = 0; } diff -u --recursive --new-file v2.1.125/linux/drivers/char/joystick/joy-db9.c linux/drivers/char/joystick/joy-db9.c --- v2.1.125/linux/drivers/char/joystick/joy-db9.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/joystick/joy-db9.c Fri Oct 9 12:20:27 1998 @@ -389,7 +389,9 @@ return port; } - info.port = parport_register_device(pp, "joystick (db9)", NULL, js_db9_wakeup, NULL, 0, NULL); + info.port = parport_register_device(pp, "joystick (db9)", NULL, js_db9_wakeup, NULL, PARPORT_DEV_EXCL, NULL); + if (!info.port) + return port; info.wanted = 0; } #else diff -u --recursive --new-file v2.1.125/linux/drivers/char/joystick/joy-lightning.c linux/drivers/char/joystick/joy-lightning.c --- v2.1.125/linux/drivers/char/joystick/joy-lightning.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/joystick/joy-lightning.c Fri Oct 9 11:41:59 1998 @@ -295,7 +295,7 @@ #ifdef MODULE int init_module(void) #else -int __init js_l4_an_init(void) +int __init js_l4_init(void) #endif { int i, cards; diff -u --recursive --new-file v2.1.125/linux/drivers/char/joystick/joy-turbografx.c linux/drivers/char/joystick/joy-turbografx.c --- v2.1.125/linux/drivers/char/joystick/joy-turbografx.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/joystick/joy-turbografx.c Fri Oct 9 12:20:27 1998 @@ -217,7 +217,9 @@ return port; } - info.port = parport_register_device(pp, "joystick (turbografx)", NULL, js_tg_wakeup, NULL, 0, NULL); + info.port = parport_register_device(pp, "joystick (turbografx)", NULL, js_tg_wakeup, NULL, PARPORT_DEV_EXCL, NULL); + if (!info.port) + return port; info.wanted = 0; info.use = 0; } diff -u --recursive --new-file v2.1.125/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.125/linux/drivers/char/lp.c Wed Sep 9 14:51:07 1998 +++ linux/drivers/char/lp.c Fri Oct 9 12:20:27 1998 @@ -768,7 +768,7 @@ lp_table[nr].dev = parport_register_device(port, "lp", lp_preempt, NULL, lp_interrupt, - PARPORT_DEV_TRAN, + 0, (void *) &lp_table[nr]); if (lp_table[nr].dev == NULL) return 1; diff -u --recursive --new-file v2.1.125/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.1.125/linux/drivers/char/misc.c Mon Sep 28 10:51:33 1998 +++ linux/drivers/char/misc.c Fri Oct 9 12:30:15 1998 @@ -66,7 +66,6 @@ extern int adbdev_init(void); extern int bus_mouse_init(void); -extern int psaux_init(void); extern int qpmouse_init(void); extern int ms_bus_mouse_init(void); extern int atixl_busmouse_init(void); @@ -156,8 +155,13 @@ } if (misc->minor < DYNAMIC_MINORS) misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7); - misc->next = &misc_list; - misc->prev = misc_list.prev; + + /* + * Add it to the front, so that later devices can "override" + * earlier defaults + */ + misc->prev = &misc_list; + misc->next = misc_list.next; misc->prev->next = misc; misc->next->prev = misc; return 0; @@ -199,10 +203,7 @@ bus_mouse_init(); #endif #if defined CONFIG_82C710_MOUSE - qpmouse_init(); /* This must be before psaux_init */ -#endif -#if defined CONFIG_PSMOUSE - psaux_init(); + qpmouse_init(); #endif #ifdef CONFIG_MS_BUSMOUSE ms_bus_mouse_init(); diff -u --recursive --new-file v2.1.125/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.1.125/linux/drivers/char/pc_keyb.c Mon Sep 28 10:51:33 1998 +++ linux/drivers/char/pc_keyb.c Fri Oct 9 13:19:46 1998 @@ -5,10 +5,16 @@ * See keyboard.c for the whole history. * * Major cleanup by Martin Mares, May 1997 + * + * Combined the keyboard and PS/2 mouse handling into one file, + * because they share the same hardware. + * Johan Myreen 1998-10-08. + * */ #include +#include #include #include #include @@ -18,10 +24,15 @@ #include #include #include +#include +#include +#include +#include #include #include #include +#include #include #include #include @@ -43,32 +54,69 @@ "\r\000/"; /* 0x60 - 0x6f */ #endif -unsigned char pckbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */ +static void kbd_write(int address, int data); + +static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; /* used only by send_data - set by keyboard_interrupt */ static volatile unsigned char reply_expected = 0; static volatile unsigned char acknowledge = 0; static volatile unsigned char resend = 0; + +#if defined CONFIG_PSMOUSE +/* + * PS/2 Auxiliary Device + */ + +static int __init psaux_init(void); + +static struct aux_queue *queue; /* Mouse data buffer. */ +static int aux_count = 0; + +#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) +#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) + +#define MAX_RETRIES 60 /* some aux operations take long time*/ +#if defined(__alpha__) && !defined(CONFIG_PCI) +# define AUX_IRQ 9 /* Jensen is odd indeed */ +#else +# define AUX_IRQ 12 +#endif +#endif /* CONFIG_PSMOUSE */ + /* - * Wait for keyboard controller input buffer is empty. + * Wait for keyboard controller input buffer is empty. + * + * Don't use 'jiffies' so that we don't depend on + * interrupts.. * - * Don't use 'jiffies' so that we don't depend on - * interrupts.. + * Quote from PS/2 System Reference Manual: + * + * "Address hex 0060 and address hex 0064 should be written only when + * the input-buffer-full bit and output-buffer-full bit in the + * Controller Status register are set 0." */ static inline void kb_wait(void) { unsigned long timeout = KBC_TIMEOUT; + unsigned char status; do { + status = inb_p(KBD_STATUS_REG); + if (status & KBD_STAT_OBF) { + if (status & KBD_STAT_MOUSE_OBF) + inb_p(KBD_DATA_REG); /* Flush. */ + } + if (! (inb_p(KBD_STATUS_REG) & KBD_STAT_IBF)) return; mdelay(1); timeout--; } while (timeout); #ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "Keyboard timed out\n"); + printk(KERN_WARNING "Keyboard timed out[1]\n"); #endif } @@ -211,11 +259,16 @@ #if DISABLE_KBD_DURING_INTERRUPTS static inline void send_cmd(unsigned char c) { + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); kb_wait(); outb(c, KBD_CNTL_REG); + spin_unlock_irqrestore(&kbd_controller_lock, flags); } -#define disable_keyboard() do { send_cmd(KBD_CCMD_KBD_DISABLE); kb_wait(); } while (0) +/* #define disable_keyboard() do { send_cmd(KBD_CCMD_KBD_DISABLE); kb_wait(); } while (0) */ +#define disable_keyboard() send_cmd(KBD_CCMD_KBD_DISABLE) #define enable_keyboard() send_cmd(KBD_CCMD_KBD_ENABLE) #else #define disable_keyboard() /* nothing */ @@ -368,27 +421,45 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; unsigned char status; - kbd_pt_regs = regs; disable_keyboard(); + spin_lock_irqsave(&kbd_controller_lock, flags); + kbd_pt_regs = regs; - status = inb_p(KBD_STATUS_REG); - do { + status = inb(KBD_STATUS_REG); + while (status & KBD_STAT_OBF) { unsigned char scancode; - /* mouse data? */ - if (status & pckbd_read_mask & KBD_STAT_MOUSE_OBF) - break; - scancode = inb(KBD_DATA_REG); - if ((status & KBD_STAT_OBF) && do_acknowledge(scancode)) - handle_scancode(scancode); + + if (status & KBD_STAT_MOUSE_OBF) { +#ifdef CONFIG_PSMOUSE + /* Mouse data. */ + if (aux_count) { + int head = queue->head; + queue->buf[head] = scancode; + add_mouse_randomness(scancode); + head = (head + 1) & (AUX_BUF_SIZE-1); + if (head != queue->tail) { + queue->head = head; + if (queue->fasync) + kill_fasync(queue->fasync, SIGIO); + wake_up_interruptible(&queue->proc_list); + } + } +#endif + } else { + if (do_acknowledge(scancode)) + handle_scancode(scancode); + mark_bh(KEYBOARD_BH); + } status = inb(KBD_STATUS_REG); - } while (status & KBD_STAT_OBF); + } - mark_bh(KEYBOARD_BH); + spin_unlock_irqrestore(&kbd_controller_lock, flags); enable_keyboard(); } @@ -406,11 +477,10 @@ do { unsigned long timeout = KBD_TIMEOUT; - kb_wait(); - acknowledge = 0; + acknowledge = 0; /* Set by interrupt routine on receipt of ACK. */ resend = 0; reply_expected = 1; - outb_p(data, KBD_DATA_REG); + kbd_write(KBD_DATA_REG, data); for (;;) { if (acknowledge) return 1; @@ -419,7 +489,7 @@ mdelay(1); if (!--timeout) { #ifdef KBD_REPORT_TIMEOUTS - printk(KERN_WARNING "Keyboard timeout\n"); + printk(KERN_WARNING "Keyboard timeout[2]\n"); #endif return 0; } @@ -500,15 +570,29 @@ return -1; } -static void __init kbd_write(int address, int data) +static void kbd_write(int address, int data) { - int status; + unsigned long flags; - do { - status = inb(KBD_STATUS_REG); - } while (status & KBD_STAT_IBF); + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); outb(data, address); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +#if defined CONFIG_PSMOUSE +static void kbd_write_cmd(int cmd) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + outb(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); + kb_wait(); + outb(cmd, KBD_DATA_REG); + spin_unlock_irqrestore(&kbd_controller_lock, flags); } +#endif /* CONFIG_PSMOUSE */ static char * __init initialize_kbd(void) { @@ -623,6 +707,225 @@ printk(KERN_WARNING "initialize_kbd: %s\n", msg); } +#if defined CONFIG_PSMOUSE + psaux_init(); +#endif + /* Ok, finally allocate the IRQ, and off we go.. */ request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL); } + +#if defined CONFIG_PSMOUSE +/* + * Send a byte to the mouse. + */ +static void aux_write_dev(int val) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); + kb_wait(); + outb(val, KBD_DATA_REG); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +} + +static unsigned int get_from_queue(void) +{ + unsigned int result; + unsigned long flags; + + save_flags(flags); + cli(); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); + restore_flags(flags); + return result; +} + + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + +static int fasync_aux(int fd, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(fd, filp, on, &queue->fasync); + if (retval < 0) + return retval; + return 0; +} + + +static int release_aux(struct inode * inode, struct file * file) +{ + fasync_aux(-1, file, 0); + if (--aux_count) + return 0; + kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ + kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); +#ifdef CONFIG_MCA + free_irq(AUX_IRQ, inode); +#else + free_irq(AUX_IRQ, NULL); +#endif + return 0; +} + +/* + * Install interrupt handler. + * Enable auxiliary device. + */ + +static int open_aux(struct inode * inode, struct file * file) +{ + if (aux_count++) { + return 0; + } + queue->head = queue->tail = 0; /* Flush input queue */ +#ifdef CONFIG_MCA + if (request_irq(AUX_IRQ, keyboard_interrupt, MCA_bus ? SA_SHIRQ : 0, "PS/2 Mouse", inode)) { +#else + if (request_irq(AUX_IRQ, keyboard_interrupt, 0, "PS/2 Mouse", NULL)) { +#endif + aux_count--; + return -EBUSY; + } + kbd_write(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable the + auxiliary port on + controller. */ + aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */ + kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ + + return 0; +} + +/* + * Put bytes from input queue to buffer. + */ + +static ssize_t read_aux(struct file * file, char * buffer, + size_t count, loff_t *ppos) +{ + struct wait_queue wait = { current, NULL }; + ssize_t i = count; + unsigned char c; + + if (queue_empty()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&queue->proc_list, &wait); +repeat: + current->state = TASK_INTERRUPTIBLE; + if (queue_empty() && !signal_pending(current)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&queue->proc_list, &wait); + } + while (i > 0 && !queue_empty()) { + c = get_from_queue(); + put_user(c, buffer++); + i--; + } + if (count-i) { + file->f_dentry->d_inode->i_atime = CURRENT_TIME; + return count-i; + } + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +/* + * Write to the aux device. + */ + +static ssize_t write_aux(struct file * file, const char * buffer, + size_t count, loff_t *ppos) +{ + ssize_t retval = 0; + + if (count) { + ssize_t written = 0; + + if (count > 32) + count = 32; /* Limit to 32 bytes. */ + do { + char c; + get_user(c, buffer++); + aux_write_dev(c); + written++; + } while (--count); + retval = -EIO; + if (written) { + retval = written; + file->f_dentry->d_inode->i_mtime = CURRENT_TIME; + } + } + + return retval; +} + +static unsigned int aux_poll(struct file *file, poll_table * wait) +{ + poll_wait(file, &queue->proc_list, wait); + if (!queue_empty()) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations psaux_fops = { + NULL, /* seek */ + read_aux, + write_aux, + NULL, /* readdir */ + aux_poll, + NULL, /* ioctl */ + NULL, /* mmap */ + open_aux, + NULL, /* flush */ + release_aux, + NULL, + fasync_aux, +}; + +/* + * Initialize driver. + */ +static struct miscdevice psaux_mouse = { + PSMOUSE_MINOR, "psaux", &psaux_fops +}; + +static int __init psaux_init(void) +{ + if (aux_device_present != 0xaa) + return -EIO; + + printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n"); + misc_register(&psaux_mouse); + queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + memset(queue, 0, sizeof(*queue)); + queue->head = queue->tail = 0; + queue->proc_list = NULL; + +#ifdef INITIALIZE_MOUSE + kbd_write(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux. */ + aux_write_dev(AUX_SET_SAMPLE); + aux_write_dev(100); /* 100 samples/sec */ + aux_write_dev(AUX_SET_RES); + aux_write_dev(3); /* 8 counts per mm */ + aux_write_dev(AUX_SET_SCALE21); /* 2:1 scaling */ +#endif /* INITIALIZE_MOUSE */ + kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable aux device. */ + kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ + + return 0; +} + +#endif /* CONFIG_PSMOUSE */ diff -u --recursive --new-file v2.1.125/linux/drivers/char/pc_keyb.h linux/drivers/char/pc_keyb.h --- v2.1.125/linux/drivers/char/pc_keyb.h Sat Sep 5 16:46:40 1998 +++ linux/drivers/char/pc_keyb.h Fri Oct 9 11:44:19 1998 @@ -14,6 +14,9 @@ #define KBD_REPORT_UNKN /* Report unknown scan codes */ #define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ #undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ +#undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ + + #define KBD_INIT_TIMEOUT 1000 /* Timeout in ms for initializing the keyboard */ #define KBC_TIMEOUT 250 /* Timeout in ms for sending to keyboard controller */ @@ -109,3 +112,13 @@ #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ #define AUX_RESET 0xFF /* Reset aux device */ + +#define AUX_BUF_SIZE 2048 + +struct aux_queue { + unsigned long head; + unsigned long tail; + struct wait_queue *proc_list; + struct fasync_struct *fasync; + unsigned char buf[AUX_BUF_SIZE]; +}; diff -u --recursive --new-file v2.1.125/linux/drivers/char/psaux.c linux/drivers/char/psaux.c --- v2.1.125/linux/drivers/char/psaux.c Mon Sep 28 10:51:33 1998 +++ linux/drivers/char/psaux.c Wed Dec 31 16:00:00 1969 @@ -1,452 +0,0 @@ -/* - * linux/drivers/char/psaux.c - * - * Driver for PS/2 type mouse by Johan Myreen. - * - * Supports pointing devices attached to a PS/2 type - * Keyboard and Auxiliary Device Controller. - * - * Corrections in device setup for some laptop mice & trackballs. - * 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca) - * - * Changed to prevent keyboard lockups on AST Power Exec. - * 28Jul93 Brad Bosch - brad@lachman.com - * - * Added support for SIGIO. 28Jul95 jem@pandora.pp.fi - * - * Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com - * - * Modularised 8-Sep-95 Philip Blundell - * - * Fixed keyboard lockups at open time - * 3-Jul-96, 22-Aug-96 Roman Hodek - * - * Cleanup by Martin Mares, 01-Jun-97 (now uses the new PC kbd include) - * - * Renamed misc. name to "psaux",more in keeping with Documentation/devices.txt - * 13-Jan-1998, Richard Gooch - */ - -/* - * This really should be part of the pc_kbd driver - they share the same - * controller, and right now we have ridiculous synchronization problems. - * Some of the SMP bootup problems may be due to not getting synchronization - * right. - * - * I moved the C&T mouse driver to a file of its own, hopefully that will - * make it easier to eventually fix this all. - * - * Linus - */ - -/* Uncomment the following line if your mouse needs initialization. */ - -/* #define INITIALIZE_DEVICE */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "pc_keyb.h" - -/* - * Generic declarations for both PS2 and 82C710 - */ - -#define PSMOUSE_MINOR 1 /* Minor device # for this mouse */ -#define AUX_BUF_SIZE 2048 - -struct aux_queue { - unsigned long head; - unsigned long tail; - struct wait_queue *proc_list; - struct fasync_struct *fasync; - unsigned char buf[AUX_BUF_SIZE]; -}; - -static struct aux_queue *queue; -static int aux_count = 0; - -static unsigned int get_from_queue(void) -{ - unsigned int result; - unsigned long flags; - - save_flags(flags); - cli(); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - restore_flags(flags); - return result; -} - - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static int fasync_aux(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - -/* - * PS/2 Aux Device - */ - -#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) -#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) - -#define MAX_RETRIES 60 /* some aux operations take long time*/ -#if defined(__alpha__) && !defined(CONFIG_PCI) -# define AUX_IRQ 9 /* Jensen is odd indeed */ -#else -# define AUX_IRQ 12 -#endif - -/* - * Status polling - */ - -static int poll_aux_status(void) -{ - int retries=0; - - while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) { - if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) - inb_p(KBD_DATA_REG); - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (5*HZ + 99) / 100; - schedule(); - retries++; - } - return (retries < MAX_RETRIES); -} - -/* - * Write to aux device - */ - -static void aux_write_dev(int val) -{ - poll_aux_status(); - outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); /* Write magic cookie */ - poll_aux_status(); - outb_p(val, KBD_DATA_REG); /* Write data */ -} - -/* - * Write to device & handle returned ack - */ - -#ifdef INITIALIZE_DEVICE -__initfunc(static int aux_write_ack(int val)) -{ - aux_write_dev(val); - poll_aux_status(); - - if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF) - { - return (inb(KBD_DATA_REG)); - } - return 0; -} -#endif /* INITIALIZE_DEVICE */ - -/* - * Write aux device command - */ - -static void aux_write_cmd(int val) -{ - poll_aux_status(); - outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); - poll_aux_status(); - outb_p(val, KBD_DATA_REG); -} - -/* - * AUX handler critical section start and end. - * - * Only one process can be in the critical section and all keyboard sends are - * deferred as long as we're inside. This is necessary as we may sleep when - * waiting for the keyboard controller and other processes / BH's can - * preempt us. Please note that the input buffer must be flushed when - * aux_end_atomic() is called and the interrupt is no longer enabled as not - * doing so might cause the keyboard driver to ignore all incoming keystrokes. - */ - -static struct semaphore aux_sema4 = MUTEX; - -static inline void aux_start_atomic(void) -{ - down(&aux_sema4); - disable_bh(KEYBOARD_BH); -} - -static inline void aux_end_atomic(void) -{ - enable_bh(KEYBOARD_BH); - up(&aux_sema4); -} - -/* - * Interrupt from the auxiliary device: a character - * is waiting in the keyboard/aux controller. - */ - -static void aux_interrupt(int cpl, void *dev_id, struct pt_regs * regs) -{ - int head = queue->head; - int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1); - - if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF) - return; - - add_mouse_randomness(queue->buf[head] = inb(KBD_DATA_REG)); - if (head != maxhead) { - head++; - head &= AUX_BUF_SIZE-1; - } - queue->head = head; - if (queue->fasync) - kill_fasync(queue->fasync, SIGIO); - wake_up_interruptible(&queue->proc_list); -} - -static int release_aux(struct inode * inode, struct file * file) -{ - fasync_aux(-1, file, 0); - if (--aux_count) - return 0; -#ifdef CONFIG_VT - pckbd_read_mask = KBD_STAT_OBF; -#endif - aux_start_atomic(); - aux_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ - poll_aux_status(); - outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */ - poll_aux_status(); - aux_end_atomic(); -#ifdef CONFIG_MCA - free_irq(AUX_IRQ, inode); -#else - free_irq(AUX_IRQ, NULL); -#endif - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * Install interrupt handler. - * Enable auxiliary device. - */ - -static int open_aux(struct inode * inode, struct file * file) -{ - aux_start_atomic(); - if (aux_count++) { - aux_end_atomic(); - return 0; - } - if (!poll_aux_status()) { /* FIXME: Race condition */ - aux_count--; - aux_end_atomic(); - return -EBUSY; - } - queue->head = queue->tail = 0; /* Flush input queue */ -#ifdef CONFIG_MCA - if (request_irq(AUX_IRQ, aux_interrupt, MCA_bus ? SA_SHIRQ : 0, "PS/2 Mouse", inode)) { -#else - if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)) { -#endif - aux_count--; - aux_end_atomic(); - return -EBUSY; - } - MOD_INC_USE_COUNT; - poll_aux_status(); - outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */ - aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */ - aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */ - poll_aux_status(); - aux_end_atomic(); - -#ifdef CONFIG_VT - pckbd_read_mask = AUX_STAT_OBF; -#endif - - return 0; -} - -/* - * Write to the aux device. - */ - -static ssize_t write_aux(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - ssize_t retval = 0; - - if (count) { - ssize_t written = 0; - - aux_start_atomic(); - do { - char c; - if (!poll_aux_status()) - break; - outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG); - if (!poll_aux_status()) - break; - get_user(c, buffer++); - outb_p(c, KBD_DATA_REG); - written++; - } while (--count); - aux_end_atomic(); - retval = -EIO; - if (written) { - retval = written; - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - } - } - - return retval; -} - -/* - * Put bytes from input queue to buffer. - */ - -static ssize_t read_aux(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - struct wait_queue wait = { current, NULL }; - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - current->state = TASK_INTERRUPTIBLE; - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -static unsigned int aux_poll(struct file *file, poll_table * wait) -{ - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations psaux_fops = { - NULL, /* seek */ - read_aux, - write_aux, - NULL, /* readdir */ - aux_poll, - NULL, /* ioctl */ - NULL, /* mmap */ - open_aux, - NULL, /* flush */ - release_aux, - NULL, - fasync_aux, -}; - -/* - * Initialize driver. - */ -static struct miscdevice psaux_mouse = { - PSMOUSE_MINOR, "psaux", &psaux_fops -}; - -__initfunc(int psaux_init(void)) -{ - if (aux_device_present != 0xaa) - return -EIO; - - printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n"); - misc_register(&psaux_mouse); - queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - queue->proc_list = NULL; - - aux_start_atomic(); -#ifdef INITIALIZE_DEVICE - outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */ - aux_write_ack(AUX_SET_SAMPLE); - aux_write_ack(100); /* 100 samples/sec */ - aux_write_ack(AUX_SET_RES); - aux_write_ack(3); /* 8 counts per mm */ - aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ - poll_aux_status(); -#endif /* INITIALIZE_DEVICE */ - outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */ - poll_aux_status(); - outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); /* Disable controller interrupts */ - poll_aux_status(); - outb_p(AUX_INTS_OFF, KBD_DATA_REG); - poll_aux_status(); - aux_end_atomic(); - - return 0; -} - -#ifdef MODULE -int init_module(void) -{ - return psaux_init(); -} - -void cleanup_module(void) -{ - misc_deregister(&psaux_mouse); - kfree(queue); -} -#endif diff -u --recursive --new-file v2.1.125/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.1.125/linux/drivers/char/qpmouse.c Mon Sep 28 10:51:33 1998 +++ linux/drivers/char/qpmouse.c Fri Oct 9 11:44:19 1998 @@ -8,15 +8,15 @@ * Corrections in device setup for some laptop mice & trackballs. * 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca) * - * Modified by Johan Myreen (jem@pandora.pp.fi) 04Aug93 + * Modified by Johan Myreen (jem@iki.fi) 04Aug93 * to include support for QuickPort mouse. * * Changed references to "QuickPort" with "82C710" since "QuickPort" * is not what this driver is all about -- QuickPort is just a * connector type, and this driver is for the mouse port on the Chips - * & Technologies 82C710 interface chip. 15Nov93 jem@pandora.pp.fi + * & Technologies 82C710 interface chip. 15Nov93 jem@iki.fi * - * Added support for SIGIO. 28Jul95 jem@pandora.pp.fi + * Added support for SIGIO. 28Jul95 jem@iki.fi * * Rearranged SIGIO support to use code from tty_io. 9Sept95 ctm@ardi.com * diff -u --recursive --new-file v2.1.125/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c --- v2.1.125/linux/drivers/char/sysrq.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/sysrq.c Wed Oct 14 11:43:13 1998 @@ -168,7 +168,14 @@ case IDE1_MAJOR: case IDE2_MAJOR: case IDE3_MAJOR: - case SCSI_DISK_MAJOR: + case SCSI_DISK0_MAJOR: + case SCSI_DISK1_MAJOR: + case SCSI_DISK2_MAJOR: + case SCSI_DISK3_MAJOR: + case SCSI_DISK4_MAJOR: + case SCSI_DISK5_MAJOR: + case SCSI_DISK6_MAJOR: + case SCSI_DISK7_MAJOR: return 1; default: return 0; diff -u --recursive --new-file v2.1.125/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- v2.1.125/linux/drivers/char/tpqic02.c Wed Aug 26 11:37:37 1998 +++ linux/drivers/char/tpqic02.c Fri Oct 9 11:56:59 1998 @@ -1360,6 +1360,7 @@ */ static inline void dma_transfer(void) { + unsigned long flags; if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */ outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT); /* back to normal */ @@ -1369,6 +1370,7 @@ outb_p(ctlbits, QIC02_CTL_PORT); + flags=claim_dma_lock(); clear_dma_ff(QIC02_TAPE_DMA); set_dma_mode(QIC02_TAPE_DMA, dma_mode); set_dma_addr(QIC02_TAPE_DMA, buffaddr+dma_bytes_done); /* full address */ @@ -1393,6 +1395,9 @@ /* start computer DMA controller */ enable_dma(QIC02_TAPE_DMA); + + release_dma_lock(flags); + /* block transfer should start now, jumping to the * interrupt routine when done or an exception was detected. */ @@ -1410,6 +1415,7 @@ /* assume 'bytes_todo'>0 */ { int stat; + unsigned long flags; tpqputs(TPQD_DEBUG, "start_dma() enter"); TPQDEB({printk(TPQIC02_NAME ": doing_read==%d, doing_write==%d\n", doing_read, doing_write);}) @@ -1506,9 +1512,10 @@ /* initiate first data block read from/write to the tape controller */ + save_flags(flags); cli(); dma_transfer(); - sti(); + restore_flags(flags); TPQPUTS("start_dma() end"); return TE_OK; @@ -1524,13 +1531,18 @@ static void end_dma(unsigned long * bytes_done) { int stat = TE_OK; + unsigned long flags; TIMEROFF; TPQPUTS("end_dma() enter"); + flags=claim_dma_lock(); + disable_dma(QIC02_TAPE_DMA); clear_dma_ff(QIC02_TAPE_DMA); + + release_dma_lock(flags); if (QIC02_TAPE_IFC == WANGTEK) /* or EVEREX */ outb_p(WT_CTL_ONLINE, QIC02_CTL_PORT); /* back to normal */ @@ -1633,6 +1645,7 @@ static void qic02_tape_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int stat, r, i; + unsigned long flags; TIMEROFF; @@ -1682,10 +1695,14 @@ r = 1; } + flags=claim_dma_lock(); + if ( (i = get_dma_residue(QIC02_TAPE_DMA)) != 0 ) { printk(TPQIC02_NAME ": dma_residue == %x !!!\n", i); r = 1; /* big trouble, but can't do much about it... */ } + + release_dma_lock(flags); if (r) return; diff -u --recursive --new-file v2.1.125/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.125/linux/drivers/char/tty_io.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/tty_io.c Tue Oct 13 11:42:18 1998 @@ -1132,7 +1132,6 @@ * both sides, and we've completed the last operation that could * block, so it's safe to proceed with closing. */ - if (pty_master) { if (--o_tty->count < 0) { printk("release_dev: bad pty slave count (%d) for %s\n", @@ -1147,6 +1146,16 @@ } /* + * We've decremented tty->count, so we should zero out + * filp->private_data, to break the link between the tty and + * the file descriptor. Otherwise if close_fp() blocks before + * the the file descriptor is removed from the inuse_filp + * list, check_tty_count() could observe a discrepancy and + * printk a warning message to the user. + */ + filp->private_data = 0; + + /* * Perform some housekeeping before deciding whether to return. * * Set the TTY_CLOSING flag if this was the last open. In the @@ -1180,7 +1189,6 @@ /* check whether both sides are closing ... */ if (!tty_closing || (o_tty && !o_tty_closing)) return; - filp->private_data = 0; #ifdef TTY_DEBUG_HANGUP printk("freeing tty structure..."); @@ -1293,7 +1301,6 @@ return retval; #ifdef CONFIG_UNIX98_PTYS - /* N.B. this error exit may leave filp->f_flags with O_NONBLOCK set */ init_dev_done: #endif filp->private_data = tty; @@ -2084,6 +2091,7 @@ if (tty_register_driver(&dev_syscons_driver)) panic("Couldn't register /dev/console driver\n"); +#ifdef CONFIG_UNIX98_PTYS dev_ptmx_driver = dev_tty_driver; dev_ptmx_driver.driver_name = "/dev/ptmx"; dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5; @@ -2094,7 +2102,8 @@ if (tty_register_driver(&dev_ptmx_driver)) panic("Couldn't register /dev/ptmx driver\n"); - +#endif + #ifdef CONFIG_VT dev_console_driver = dev_tty_driver; dev_console_driver.driver_name = "/dev/tty0"; diff -u --recursive --new-file v2.1.125/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c --- v2.1.125/linux/drivers/misc/parport_arc.c Tue Jul 21 00:15:31 1998 +++ linux/drivers/misc/parport_arc.c Fri Oct 9 12:20:27 1998 @@ -33,6 +33,11 @@ /* ARC can't read from the data latch, so we must use a soft copy. */ static unsigned char data_copy; +static void arc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + parport_generic_irq(irq, (struct parport *) dev_id, regs); +} + static void arc_write_data(struct parport *p, unsigned char data) { data_copy = data; @@ -110,7 +115,7 @@ arc_enable_irq, arc_disable_irq, - arc_examine_irq, + arc_interrupt, arc_inc_use_count, arc_dec_use_count, diff -u --recursive --new-file v2.1.125/linux/drivers/misc/parport_ax.c linux/drivers/misc/parport_ax.c --- v2.1.125/linux/drivers/misc/parport_ax.c Thu Aug 6 14:06:32 1998 +++ linux/drivers/misc/parport_ax.c Fri Oct 9 12:20:27 1998 @@ -50,10 +50,9 @@ #define CONFIGB 0x401 #define ECONTROL 0x402 -static void -parport_ax_null_intr_func(int irq, void *dev_id, struct pt_regs *regs) +static void parport_ax_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - /* NULL function - Does nothing */ + parport_generic_irq(irq, (struct parport *) dev_id, regs); } void @@ -206,7 +205,7 @@ { if (p->irq != PARPORT_IRQ_NONE) { parport_ax_disable_irq(p); - free_irq(p->irq, NULL); + free_irq(p->irq, p); } release_region(p->base, p->size); if (p->modes & PARPORT_MODE_PCECR) @@ -219,11 +218,15 @@ parport_ax_claim_resources(struct parport *p) { /* FIXME check that resources are free */ - if (p->irq != PARPORT_IRQ_NONE) { - request_irq(p->irq, parport_ax_null_intr_func, - 0, p->name, NULL); - parport_ax_enable_irq(p); - } + int err; + + if (p->irq != PARPORT_IRQ_NONE) + if ((err = request_irq(p->irq, parport_ax_interrupt, + 0, p->name, p)) != 0) + return err; + else + parport_ax_enable_irq(p); + request_region(p->base, p->size, p->name); if (p->modes & PARPORT_MODE_PCECR) request_region(p->base+0x400, 3, p->name); @@ -281,12 +284,6 @@ return 0; /* FIXME */ } -int -parport_ax_examine_irq(struct parport *p) -{ - return 0; /* FIXME */ -} - void parport_ax_inc_use_count(void) { @@ -355,7 +352,7 @@ parport_ax_enable_irq, parport_ax_disable_irq, - parport_ax_examine_irq, + parport_ax_interrupt, parport_ax_inc_use_count, parport_ax_dec_use_count, diff -u --recursive --new-file v2.1.125/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.1.125/linux/drivers/misc/parport_pc.c Wed Sep 9 14:51:07 1998 +++ linux/drivers/misc/parport_pc.c Fri Oct 9 12:20:27 1998 @@ -1,4 +1,4 @@ -/* Low-level parallel-port routines for PC-style hardware. +/* Low-level parallel-port routines for 8255-based PC-style hardware. * * Authors: Phil Blundell * Tim Waugh @@ -32,13 +32,8 @@ * accomodate this. */ -#include -#include - -#include -#include - #include +#include #include #include #include @@ -46,6 +41,8 @@ #include #include +#include + #include #include @@ -53,9 +50,9 @@ than PARPORT_MAX (in ). */ #define PARPORT_PC_MAX_PORTS 8 -static void parport_pc_null_intr_func(int irq, void *dev_id, struct pt_regs *regs) +static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - /* Null function - does nothing */ + parport_generic_irq(irq, (struct parport *) dev_id, regs); } void parport_pc_write_epp(struct parport *p, unsigned char d) @@ -173,7 +170,7 @@ void parport_pc_release_resources(struct parport *p) { if (p->irq != PARPORT_IRQ_NONE) - free_irq(p->irq, NULL); + free_irq(p->irq, p); release_region(p->base, p->size); if (p->modes & PARPORT_MODE_PCECR) release_region(p->base+0x400, 3); @@ -183,7 +180,9 @@ { int err; if (p->irq != PARPORT_IRQ_NONE) - if ((err = request_irq(p->irq, parport_pc_null_intr_func, 0, p->name, NULL)) != 0) return err; + if ((err = request_irq(p->irq, parport_pc_interrupt, + 0, p->name, p)) != 0) + return err; request_region(p->base, p->size, p->name); if (p->modes & PARPORT_MODE_PCECR) request_region(p->base+0x400, 3, p->name); @@ -242,11 +241,6 @@ return -ENOSYS; /* FIXME */ } -int parport_pc_examine_irq(struct parport *p) -{ - return 0; /* FIXME */ -} - void parport_pc_inc_use_count(void) { #ifdef MODULE @@ -313,7 +307,7 @@ parport_pc_enable_irq, parport_pc_disable_irq, - parport_pc_examine_irq, + parport_pc_interrupt, parport_pc_inc_use_count, parport_pc_dec_use_count, diff -u --recursive --new-file v2.1.125/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c --- v2.1.125/linux/drivers/misc/parport_procfs.c Wed Sep 9 14:51:07 1998 +++ linux/drivers/misc/parport_procfs.c Fri Oct 9 12:20:27 1998 @@ -29,16 +29,13 @@ 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) + unsigned long count, void *data) { int retval = -EINVAL; int newirq = PARPORT_IRQ_NONE; struct parport *pp = (struct parport *)data; int oldirq = pp->irq; - unsigned long flags; /* * We can have these valid cases: @@ -70,30 +67,44 @@ if (oldirq == newirq) goto out; - spin_lock_irqsave(&pp->lock, flags); if (pp->flags & PARPORT_FLAG_COMA) goto out_ok; retval = -EBUSY; + + /* + * Here we don' t need the irq version of spinlocks because + * the parport_lowlevel irq handler must not change the cad, + * and so has no one reason to write_lock() the cad_lock spinlock. + * -arca + */ + read_lock(&pp->cad_lock); + if (pp->cad) - goto out_unlock; + { + read_unlock(&pp->cad_lock); + return retval; + } if (newirq != PARPORT_IRQ_NONE) { - retval = request_irq(newirq, parport_null_intr_func, - SA_INTERRUPT, pp->name, NULL); + retval = request_irq(newirq, pp->ops->interrupt, + 0, pp->name, pp); if (retval) - goto out_unlock; - else retval = count; + { + read_unlock(&pp->cad_lock); + return retval; + } } if (oldirq != PARPORT_IRQ_NONE) - free_irq(oldirq, NULL); + free_irq(oldirq, pp); + + retval = count; + + read_unlock(&pp->cad_lock); out_ok: pp->irq = newirq; - -out_unlock: - spin_unlock_irqrestore (&pp->lock, flags); out: return retval; diff -u --recursive --new-file v2.1.125/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c --- v2.1.125/linux/drivers/misc/parport_share.c Wed Sep 9 14:51:07 1998 +++ linux/drivers/misc/parport_share.c Fri Oct 9 12:20:27 1998 @@ -27,6 +27,7 @@ #include #include +#include #ifdef CONFIG_KMOD #include @@ -55,19 +56,12 @@ return portlist; } -void parport_null_intr_func(int irq, void *dev_id, struct pt_regs *regs) -{ - /* 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, struct parport_operations *ops) { struct parport *tmp; int portnum; char *name; - unsigned long flags; /* Check for a previously registered port. NOTE: we will ignore irq and dma if we find a previously @@ -111,7 +105,9 @@ tmp->ops = ops; tmp->number = portnum; memset (&tmp->probe_info, 0, sizeof (struct parport_device_info)); - spin_lock_init (&tmp->lock); + spin_lock_init(&tmp->cad_lock); + spin_lock_init(&tmp->waitlist_lock); + spin_lock_init(&tmp->pardevice_lock); name = kmalloc(15, GFP_KERNEL); if (!name) { @@ -122,14 +118,19 @@ sprintf(name, "parport%d", portnum); tmp->name = name; - /* Chain the entry to our list. */ - spin_lock_irqsave (&parportlist_lock, flags); + /* + * Chain the entry to our list. + * + * This function must not run from an irq handler so we don' t need + * to clear irq on the local CPU. -arca + */ + spin_lock(&parportlist_lock); if (portlist_tail) portlist_tail->next = tmp; portlist_tail = tmp; if (!portlist) portlist = tmp; - spin_unlock_irqrestore (&parportlist_lock, flags); + spin_unlock(&parportlist_lock); tmp->probe_info.class = PARPORT_CLASS_LEGACY; /* assume the worst */ tmp->waithead = tmp->waittail = NULL; @@ -140,8 +141,8 @@ void parport_unregister_port(struct parport *port) { struct parport *p; - unsigned long flags; - spin_lock_irqsave (&parportlist_lock, flags); + + spin_lock(&parportlist_lock); if (portlist == port) { if ((portlist = port->next) == NULL) portlist_tail = NULL; @@ -155,7 +156,7 @@ else printk (KERN_WARNING "%s not found in port list!\n", port->name); } - spin_unlock_irqrestore (&parportlist_lock, flags); + spin_unlock(&parportlist_lock); if (port->probe_info.class_name) kfree (port->probe_info.class_name); if (port->probe_info.mfr) @@ -195,7 +196,13 @@ int flags, void *handle) { struct pardevice *tmp; - unsigned long flgs; + + if (port->flags & PARPORT_FLAG_EXCL) { + /* An exclusive device is registered. */ + printk (KERN_DEBUG "%s: no more devices allowed\n", + port->name); + return NULL; + } if (flags & PARPORT_DEV_LURK) { if (!pf || !kf) { @@ -242,12 +249,30 @@ /* Chain this onto the list */ tmp->prev = NULL; - spin_lock_irqsave (&port->lock, flgs); + /* + * This function must not run from an irq handler so we don' t need + * to clear irq on the local CPU. -arca + */ + spin_lock(&port->pardevice_lock); + + if (flags & PARPORT_DEV_EXCL) { + if (port->devices) { + spin_unlock (&port->pardevice_lock); + kfree (tmp->state); + kfree (tmp); + printk (KERN_DEBUG + "%s: cannot grant exclusive access for " + "device %s\n", port->name, name); + return NULL; + } + port->flags |= PARPORT_FLAG_EXCL; + } + tmp->next = port->devices; if (port->devices) port->devices->prev = tmp; port->devices = tmp; - spin_unlock_irqrestore (&port->lock, flgs); + spin_unlock(&port->pardevice_lock); inc_parport_count(); port->ops->inc_use_count(); @@ -262,7 +287,6 @@ void parport_unregister_device(struct pardevice *dev) { struct parport *port; - unsigned long flags; #ifdef PARPORT_PARANOID if (dev == NULL) { @@ -279,14 +303,18 @@ return; } - spin_lock_irqsave (&port->lock, flags); + spin_lock(&port->pardevice_lock); 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); + + if (dev->flags & PARPORT_DEV_EXCL) + port->flags &= ~PARPORT_FLAG_EXCL; + + spin_unlock(&port->pardevice_lock); kfree(dev->state); kfree(dev); @@ -337,7 +365,7 @@ dev->waiting = 0; /* Take ourselves out of the wait list again. */ - spin_lock_irqsave (&port->lock, flags); + spin_lock_irqsave (&port->waitlist_lock, flags); if (dev->waitprev) dev->waitprev->waitnext = dev->waitnext; else @@ -346,28 +374,27 @@ dev->waitnext->waitprev = dev->waitprev; else port->waittail = dev->waitprev; - spin_unlock_irqrestore (&port->lock, flags); + spin_unlock_irqrestore (&port->waitlist_lock, flags); dev->waitprev = dev->waitnext = NULL; } + if (oldcad && port->irq != PARPORT_IRQ_NONE && !oldcad->irq_func) + /* + * If there was an irq pending it should hopefully happen + * before return from enable_irq(). -arca + */ + enable_irq(port->irq); + + /* + * Avoid running irq handlers if the pardevice doesn' t use it. -arca + */ + if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func) + disable_irq(port->irq); + /* Now we do the change of devices */ - spin_lock_irqsave(&port->lock, flags); + write_lock_irqsave(&port->cad_lock, flags); port->cad = dev; - spin_unlock_irqrestore(&port->lock, flags); - - /* Swap the IRQ handlers. */ - 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); - } - } + write_unlock_irqrestore(&port->cad_lock, flags); /* Restore control registers */ port->ops->restore_state(port, dev->state); @@ -379,10 +406,10 @@ 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); + spin_lock_irqsave (&port->waitlist_lock, flags); if (port->cad == NULL) { /* The port got released in the meantime. */ - spin_unlock_irqrestore (&port->lock, flags); + spin_unlock_irqrestore (&port->waitlist_lock, flags); goto try_again; } if (test_and_set_bit(0, &dev->waiting) == 0) { @@ -395,7 +422,7 @@ } else port->waithead = port->waittail = dev; } - spin_unlock_irqrestore (&port->lock, flags); + spin_unlock_irqrestore (&port->waitlist_lock, flags); } return -EAGAIN; } @@ -451,19 +478,19 @@ "when not owner\n", port->name, dev->name); return; } - spin_lock_irqsave(&port->lock, flags); + write_lock_irqsave(&port->cad_lock, flags); port->cad = NULL; - spin_unlock_irqrestore(&port->lock, flags); + write_unlock_irqrestore(&port->cad_lock, flags); + + /* + * Reenable irq and so discard the eventually pending irq while + * cad is NULL. -arca + */ + if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func) + enable_irq(port->irq); /* Save control registers */ port->ops->save_state(port, dev->state); - - /* Point IRQs somewhere harmless. */ - 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); - } /* If anybody is waiting, find out who's been there longest and then wake them up. (Note: no locking required) */ diff -u --recursive --new-file v2.1.125/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.1.125/linux/drivers/net/3c505.c Wed Jun 24 22:54:06 1998 +++ linux/drivers/net/3c505.c Fri Oct 9 11:56:59 1998 @@ -327,13 +327,17 @@ { elp_device *adapter = dev->priv; if (adapter->dmaing && (jiffies > (adapter->current_dma.start_time + 10))) { - unsigned long flags; + unsigned long flags, f; printk("%s: DMA %s timed out, %d bytes left\n", dev->name, adapter->current_dma.direction ? "download" : "upload", get_dma_residue(dev->dma)); save_flags(flags); cli(); adapter->dmaing = 0; adapter->busy = 0; + + f=claim_dma_lock(); disable_dma(dev->dma); + release_dma_lock(f); + if (adapter->rx_active) adapter->rx_active--; outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev); @@ -601,6 +605,7 @@ elp_device *adapter = dev->priv; void *target; struct sk_buff *skb; + unsigned long flags; rlen = (len + 1) & ~1; skb = dev_alloc_skb(rlen + 2); @@ -632,12 +637,14 @@ outb_control(adapter->hcr_val | DIR | TCEN | DMAE, dev); + flags=claim_dma_lock(); disable_dma(dev->dma); clear_dma_ff(dev->dma); set_dma_mode(dev->dma, 0x04); /* dma read */ set_dma_addr(dev->dma, virt_to_bus(target)); set_dma_count(dev->dma, rlen); enable_dma(dev->dma); + release_dma_lock(flags); if (elp_debug >= 3) { printk("%s: rx DMA transfer started\n", dev->name); @@ -1019,6 +1026,7 @@ { elp_device *adapter = dev->priv; unsigned long target; + unsigned long flags; /* * make sure the length is even and no shorter than 60 bytes @@ -1060,7 +1068,8 @@ target = virt_to_bus(adapter->dma_buffer); } adapter->current_dma.skb = skb; - cli(); + + flags=claim_dma_lock(); disable_dma(dev->dma); clear_dma_ff(dev->dma); set_dma_mode(dev->dma, 0x48); /* dma memory -> io */ @@ -1068,6 +1077,8 @@ set_dma_count(dev->dma, nlen); outb_control(adapter->hcr_val | DMAE | TCEN, dev); enable_dma(dev->dma); + release_dma_lock(flags); + if (elp_debug >= 3) printk("%s: DMA transfer started\n", dev->name); diff -u --recursive --new-file v2.1.125/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.1.125/linux/drivers/net/eepro100.c Mon Aug 3 12:45:45 1998 +++ linux/drivers/net/eepro100.c Sat Oct 17 02:14:23 1998 @@ -1,13 +1,13 @@ /* drivers/net/eepro100.c: An Intel i82557 Ethernet driver for Linux. */ /* NOTICE: this version tested with kernels 1.3.72 and later only! - Written 1996-1997 by Donald Becker. + Written 1996-1998 by Donald Becker. This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. This driver is for the Intel EtherExpress Pro 100B boards. - It should work with other i82557 boards (if any others exist). + It should work with other i82557 and i82558 boards. To use a built-in driver, install as drivers/net/eepro100.c. To use as a module, use the compile-command at the end of the file. @@ -15,11 +15,13 @@ Center of Excellence in Space Data and Information Sciences Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771 For updates see - + http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html + There is also a mailing list based at + linux-eepro100@cesdis.gsfc.nasa.gov */ static const char *version = -"eepro100.c:v0.36 10/20/97 Donald Becker linux-eepro100@cesdis.gsfc.nasa.gov\n"; +"eepro100.c:v1.06 10/16/98 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"; /* A few user-configurable values that apply to all boards. First set are undocumented and spelled per Intel recommendations. */ @@ -33,125 +35,60 @@ /* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. Lower values use more memory, but are faster. */ -/* - * NOTE! The value of 2000 means that this optimization never gets - * used. Rationale: it seems to be broken when in low-memory situations, - * apparently when alloc_skb() can return NULL the clever list of - * copy-buffers can get buggered. - * - * My personal suspicion is that the allocation failure will cause - * us to not remove the skb from the list of available buffers, but - * we'd already have done a "skb_push()" with the data we got, so - * the buffer stays on the list but the available memory in it - * shrinks until we panic. - * - * Donald, when you fix this you can shrink this value again. - * - * Linus - */ -static int rx_copybreak = 2000; +static int rx_copybreak = 200; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ static int max_interrupt_work = 200; -#ifdef MODULE -#ifdef MODVERSIONS -#include -#endif +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */ +static int multicast_filter_limit = 64; + #include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif #include #include -#include #include #include -#include #include #include #include #include #include -#include -#include /* Processor type for cache alignment. */ -#include -#include -#include - #include #include #include - -/* A nominally proper method to handle version dependencies is to use - LINUX_VERSION_CODE in version.h, but that triggers recompiles w/'make'. */ -#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s) -#ifdef MODULE -#if (LINUX_VERSION_CODE < VERSION(1,3,0)) -#define KERNEL_1_2 -#else /* 1.3.0 */ -#if (LINUX_VERSION_CODE >= VERSION(1,3,44)) -#define NEW_MULTICAST -#define LINUX_1_4 -#else -#warning "This driver is tested for 1.3.44 and later development kernels only." -#endif /* 1.3.44 */ -#endif -#else - -#if (LINUX_VERSION_CODE >= 0x10344) -#define NEW_MULTICAST #include -#endif -#ifdef HAVE_HEADER_CACHE -#define LINUX_1_4 -#define NEW_MULTICAST -#else -#ifdef ETH_P_DDCMP /* Warning: Bogus! This means IS_LINUX_1_3. */ -#define KERNEL_1_3 -#else -#define KERNEL_1_2 -#endif -#endif +#include +#include +#include + +/* + * Module documentation + */ +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver"); +MODULE_PARM(debug, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); +MODULE_PARM(congenb, "i"); +MODULE_PARM(txfifo, "i"); +MODULE_PARM(rxfifo, "i"); +MODULE_PARM(txdmacount, "i"); +MODULE_PARM(rxdmacount, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(multicast_filter_limit, "i"); -#endif -/* This should be in a header file. */ -#if (LINUX_VERSION_CODE < VERSION(1,3,44)) -struct device *init_etherdev(struct device *dev, int sizeof_priv, - unsigned long *mem_startp); -#endif -#if LINUX_VERSION_CODE < 0x10300 -#define RUN_AT(x) (x) /* What to put in timer->expires. */ -#define DEV_ALLOC_SKB(len) alloc_skb(len, GFP_ATOMIC) -#define virt_to_bus(addr) ((unsigned long)addr) -#define bus_to_virt(addr) ((void*)addr) -#else /* 1.3.0 and later */ #define RUN_AT(x) (jiffies + (x)) -#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2) -#endif -#if (LINUX_VERSION_CODE < 0x20123) -#define test_and_set_bit(val, addr) set_bit(val, addr) -#include -#endif +#define dev_free_skb(skb) dev_kfree_skb(skb); -/* The total I/O port extent of the board. Nominally 0x18, but rounded up - for PCI allocation. */ +/* The total I/O port extent of the board. + The registers beyond 0x18 only exist on the i82558. */ #define SPEEDO3_TOTAL_SIZE 0x20 -#ifdef HAVE_DEVLIST -struct netdev_entry eepro100_drv = -{"EEPro-100", eepro100_init, SPEEDO3_TOTAL_SIZE, NULL}; -#endif - -#ifdef SPEEDO3_DEBUG -int speedo_debug = SPEEDO3_DEBUG; -#else -int speedo_debug = 3; -#endif +int speedo_debug = 0; /* Theory of Operation @@ -183,7 +120,7 @@ Despite the extra space overhead in each receive skbuff, the driver must use the simplified Rx buffer mode to assure that only a single data buffer is associated with each RxFD. The driver implements this by reserving space -for the Rx descriptor at the head of each Rx skbuff +for the Rx descriptor at the head of each Rx skbuff. The Speedo-3 has receive and command unit base addresses that are added to almost all descriptor pointers. The driver sets these to zero, so that all @@ -198,10 +135,13 @@ The driver must use the complex Tx command+descriptor mode in order to have a indirect pointer to the skbuff data section. Each Tx command block -(TxCB) is associated with a single, immediately appended Tx buffer descriptor +(TxCB) is associated with two immediately appended Tx Buffer Descriptor (TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the speedo_private data structure for each adapter instance. +The newer i82558 explicitly supports this structure, and can read the two +TxBDs in the same PCI burst as the TxCB. + This ring structure is used for all normal transmit packets, but the transmit packet descriptors aren't long enough for most non-Tx commands such as CmdConfigure. This is complicated by the possibility that the chip has @@ -290,26 +230,19 @@ #define PKT_BUF_SZ 1536 /* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT ((400*HZ)/1000) +#define TX_TIMEOUT ((800*HZ)/1000) /* How to wait for the command unit to accept a command. Typically this takes 0 ticks. */ -static inline void wait_for_cmd_done(int cmd_ioaddr) +static inline void wait_for_cmd_done(long cmd_ioaddr) { - short wait = 100; - do ; - while(inb(cmd_ioaddr) && --wait >= 0); + int wait = 100; + do ; + while(inb(cmd_ioaddr) && --wait >= 0); } /* Operational parameter that usually are not changed. */ -#ifndef PCI_VENDOR_ID_INTEL /* Now defined in linux/pci.h */ -#define PCI_VENDOR_ID_INTEL 0x8086 /* Hmmmm, how did they pick that? */ -#endif -#ifndef PCI_DEVICE_ID_INTEL_82557 -#define PCI_DEVICE_ID_INTEL_82557 0x1229 -#endif - /* The rest of these values should never change. */ /* Offsets to the various registers. @@ -364,17 +297,24 @@ u16 size; }; -/* Elements of the RxFD.status word. */ -#define RX_COMPLETE 0x8000 +/* Selected elements of the Tx/RxFD.status word. */ +enum RxFD_bits { + RxComplete=0x8000, RxOK=0x2000, + RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010, + RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002, + StatusComplete=0x8000, +}; struct TxFD { /* Transmit frame descriptor set. */ s32 status; u32 link; /* void * */ u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ s32 count; /* # of TBD (=1), Tx start thresh., etc. */ - /* This constitutes a single "TBD" entry -- we only use one. */ - u32 tx_buf_addr; /* void *, frame to be transmitted. */ - s32 tx_buf_size; /* Length of Tx frame. */ + /* This constitutes two "TBD" entries -- we only use one. */ + u32 tx_buf_addr0; /* void *, frame to be transmitted. */ + s32 tx_buf_size0; /* Length of Tx frame. */ + u32 tx_buf_addr1; /* void *, frame to be transmitted. */ + s32 tx_buf_size1; /* Length of Tx frame. */ }; /* Elements of the dump_statistics block. This block must be lword aligned. */ @@ -402,6 +342,7 @@ char devname[8]; /* Used only for kernel debugging. */ const char *product_name; struct device *next_module; + spinlock_t lock; struct TxFD tx_ring[TX_RING_SIZE]; /* Commands (usually CmdTxPacket). */ /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; @@ -409,9 +350,6 @@ /* Rx descriptor ring & addresses of receive-in-place skbuffs. */ struct RxFD *rx_ringp[RX_RING_SIZE]; struct sk_buff* rx_skbuff[RX_RING_SIZE]; -#if (LINUX_VERSION_CODE < 0x10300) /* Kernel v1.2.*. */ - struct RxFD saved_skhead[RX_RING_SIZE]; /* Saved skbuff header chunk. */ -#endif struct RxFD *last_rxf; /* Last command sent. */ struct enet_statistics stats; struct speedo_stats lstats; @@ -419,10 +357,9 @@ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - struct descriptor config_cmd; /* A configure command, with header... */ - u8 config_cmd_data[22]; /* .. and setup parameters. */ int mc_setup_frm_len; /* The length of an allocated.. */ struct descriptor *mc_setup_frm; /* ..multicast setup frame. */ + int mc_setup_busy; /* Avoid double-use of setup frame. */ char rx_mode; /* Current PROMISC/ALLMULTI setting. */ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ @@ -436,11 +373,16 @@ /* The parameters for a CmdConfigure operation. There are so many options that it would be difficult to document each bit. We mostly use the default or recommended settings. */ -const char basic_config_cmd[22] = { +const char i82557_config_cmd[22] = { 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */ 0, 0x2E, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */ 0x3f, 0x05, }; +const char i82558_config_cmd[22] = { + 22, 0x08, 0, 1, 0, 0x80, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */ + 0, 0x2E, 0, 0x60, 0x08, 0x88, + 0x68, 0, 0x40, 0xf2, 0xBD, /* 0xBD->0xFD=Force full-duplex */ + 0x31, 0x05, }; /* PHY media interface chips. */ static const char *phys[] = { @@ -452,12 +394,12 @@ S80C24, I82555, DP83840A=10, }; static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 }; -static void speedo_found1(struct device *dev, int ioaddr, int irq, - int options, int card_idx); +static void speedo_found1(struct device *dev, long ioaddr, int irq, + int card_idx); -static int read_eeprom(int ioaddr, int location); -static int mdio_read(int ioaddr, int phy_id, int location); -static int mdio_write(int ioaddr, int phy_id, int location, int value); +static int read_eeprom(long ioaddr, int location, int addr_len); +static int mdio_read(long ioaddr, int phy_id, int location); +static int mdio_write(long ioaddr, int phy_id, int location, int value); static int speedo_open(struct device *dev); static void speedo_timer(unsigned long data); static void speedo_init_rx_ring(struct device *dev); @@ -466,9 +408,7 @@ static void speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs); static int speedo_close(struct device *dev); static struct enet_statistics *speedo_get_stats(struct device *dev); -#ifdef HAVE_PRIVATE_IOCTL static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd); -#endif static void set_rx_mode(struct device *dev); @@ -477,109 +417,101 @@ /* 'options' is used to pass a transceiver override or full-duplex flag e.g. "options=16" for FD, "options=32" for 100mbps-only. */ static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -#ifdef MODULE static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; +#ifdef MODULE static int debug = -1; /* The debug level */ #endif +#ifdef honor_default_port +/* Optional driver feature to allow forcing the transceiver setting. + Not recommended. */ +static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100, + 0x2000, 0x2100, 0x0400, 0x3100}; +#endif + /* A list of all installed Speedo devices, for removing the driver module. */ static struct device *root_speedo_dev = NULL; int eepro100_init(struct device *dev) { int cards_found = 0; + static int pci_index = 0; - if (pci_present()) { - static int pci_index = 0; + if (! pcibios_present()) + return cards_found; - for (; pci_index < 8; pci_index++) { - unsigned char pci_bus, pci_device_fn, pci_latency; -#if (LINUX_VERSION_CODE >= VERSION(2,1,85)) - unsigned int pci_irq_line; - struct pci_dev *pdev; -#else - unsigned char pci_irq_line; -#endif -#if (LINUX_VERSION_CODE >= VERSION(1,3,44)) - int pci_ioaddr; -#else - long pci_ioaddr; -#endif - unsigned short pci_command; - - if (pcibios_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82557, - pci_index, &pci_bus, - &pci_device_fn)) - break; -#if (LINUX_VERSION_CODE >= VERSION(2,1,85)) - pdev = pci_find_slot(pci_bus, pci_device_fn); - pci_irq_line = pdev->irq; - pci_ioaddr = pdev->base_address[1]; -#else - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - /* Note: BASE_ADDRESS_0 is for memory-mapping the registers. */ - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, &pci_ioaddr); -#endif - /* Remove I/O space marker in bit 0. */ - pci_ioaddr &= ~3; - if (speedo_debug > 2) - printk("Found Intel i82557 PCI Speedo at I/O %#x, IRQ %d.\n", - (int)pci_ioaddr, pci_irq_line); - - /* Get and check the bus-master and latency values. */ - pcibios_read_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, &pci_command); - if ( ! (pci_command & PCI_COMMAND_MASTER)) { - printk(" PCI Master Bit has not been set! Setting...\n"); - pci_command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, pci_device_fn, - PCI_COMMAND, pci_command); - } - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < 10) { - printk(" PCI latency timer (CFLT) is unreasonably low at %d." - " Setting to 255 clocks.\n", pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 255); - } else if (speedo_debug > 1) - printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); - -#ifdef MODULE - speedo_found1(dev, pci_ioaddr, pci_irq_line, options[cards_found], - cards_found); -#else - speedo_found1(dev, pci_ioaddr, pci_irq_line, - dev ? dev->mem_start : 0, -1); -#endif - dev = NULL; - cards_found++; + for (; pci_index < 8; pci_index++) { + unsigned char pci_bus, pci_device_fn, pci_latency; + long ioaddr; + int irq; + + u16 pci_command, new_command; + + if (pcibios_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82557, + pci_index, &pci_bus, + &pci_device_fn)) + break; + { + struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); + ioaddr = pdev->base_address[1]; /* Use [0] to mem-map */ + irq = pdev->irq; } + /* Remove I/O space marker in bit 0. */ + ioaddr &= ~3; + if (speedo_debug > 2) + printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n", + ioaddr, irq); + + /* Get and check the bus-master and latency values. */ + pcibios_read_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, &pci_command); + new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; + if (pci_command != new_command) { + printk(KERN_INFO " The PCI BIOS has not enabled this" + " device! Updating PCI command %4.4x->%4.4x.\n", + pci_command, new_command); + pcibios_write_config_word(pci_bus, pci_device_fn, + PCI_COMMAND, new_command); + } + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < 32) { + printk(" PCI latency timer (CFLT) is unreasonably low at %d." + " Setting to 32 clocks.\n", pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 32); + } else if (speedo_debug > 1) + printk(" PCI latency timer (CFLT) is %#x.\n", pci_latency); + + speedo_found1(dev, ioaddr, irq, cards_found); + dev = NULL; + cards_found++; } return cards_found; } -static void speedo_found1(struct device *dev, int ioaddr, int irq, int options, +static void speedo_found1(struct device *dev, long ioaddr, int irq, int card_idx) { static int did_version = 0; /* Already printed version info. */ struct speedo_private *sp; char *product; - int i; + int i, option; u16 eeprom[0x40]; if (speedo_debug > 0 && did_version++ == 0) printk(version); -#if (LINUX_VERSION_CODE >= VERSION(1,3,44)) dev = init_etherdev(dev, sizeof(struct speedo_private)); -#else - dev = init_etherdev(dev, sizeof(struct speedo_private), 0); -#endif + + if (dev->mem_start > 0) + option = dev->mem_start; + else if (card_idx >= 0 && options[card_idx] >= 0) + option = options[card_idx]; + else + option = 0; /* Read the station address EEPROM before doing the reset. Perhaps this should even be done before accepting the device, @@ -587,8 +519,10 @@ { u16 sum = 0; int j; + int addr_len = read_eeprom(ioaddr, 0, 6) == 0xffff ? 8 : 6; + for (j = 0, i = 0; i < 0x40; i++) { - u16 value = read_eeprom(ioaddr, i); + u16 value = read_eeprom(ioaddr, i, addr_len); eeprom[i] = value; sum += value; if (i < 3) { @@ -614,7 +548,7 @@ else product = "Intel EtherExpress Pro 10/100"; - printk(KERN_INFO "%s: %s at %#3x, ", dev->name, product, ioaddr); + printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr); for (i = 0; i < 5; i++) printk("%2.2X:", dev->dev_addr[i]); @@ -643,17 +577,6 @@ if (eeprom[7] & 0x0700) printk(KERN_INFO " Secondary interface chip %s.\n", phys[(eeprom[7]>>8)&7]); -#if defined(notdef) - /* ToDo: Read and set PHY registers through MDIO port. */ - for (i = 0; i < 2; i++) - printk(KERN_INFO" MDIO register %d is %4.4x.\n", - i, mdio_read(ioaddr, eeprom[6] & 0x1f, i)); - for (i = 5; i < 7; i++) - printk(KERN_INFO" MDIO register %d is %4.4x.\n", - i, mdio_read(ioaddr, eeprom[6] & 0x1f, i)); - printk(KERN_INFO" MDIO register %d is %4.4x.\n", - 25, mdio_read(ioaddr, eeprom[6] & 0x1f, 25)); -#endif if (((eeprom[6]>>8) & 0x3f) == DP83840 || ((eeprom[6]>>8) & 0x3f) == DP83840A) { int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422; @@ -663,13 +586,13 @@ mdi_reg23); mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23); } - if ((options >= 0) && (options & 0x60)) { + if ((option >= 0) && (option & 0x70)) { printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", - (options & 0x20 ? 100 : 10), - (options & 0x10 ? "full" : "half")); + (option & 0x20 ? 100 : 10), + (option & 0x10 ? "full" : "half")); mdio_write(ioaddr, eeprom[6] & 0x1f, 0, - ((options & 0x20) ? 0x2000 : 0) | /* 100mbps? */ - ((options & 0x10) ? 0x0100 : 0)); /* Full duplex? */ + ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ + ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ } /* Perform a system self-test. */ @@ -678,11 +601,7 @@ self_test_results[1] = -1; outl(virt_to_bus(self_test_results) | 1, ioaddr + SCBPort); do { -#ifdef _LINUX_DELAY_H udelay(10); -#else - SLOW_DOWN_IO; -#endif } while (self_test_results[1] == -1 && --boguscnt >= 0); if (boguscnt < 0) { /* Test optimized out. */ @@ -704,8 +623,6 @@ } #endif /* kernel_bloat */ - outl(0, ioaddr + SCBPort); - /* We do a request_region() only to register /proc/ioports info. */ request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet"); @@ -719,12 +636,12 @@ sp->next_module = root_speedo_dev; root_speedo_dev = dev; + sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; if (card_idx >= 0) { if (full_duplex[card_idx] >= 0) sp->full_duplex = full_duplex[card_idx]; - } else - sp->full_duplex = options >= 0 && (options & 0x10) ? 1 : 0; - sp->default_port = options >= 0 ? (options & 0x0f) : 0; + } + sp->default_port = option >= 0 ? (option & 0x0f) : 0; sp->phy[0] = eeprom[6]; sp->phy[1] = eeprom[7]; @@ -738,12 +655,8 @@ dev->hard_start_xmit = &speedo_start_xmit; dev->stop = &speedo_close; dev->get_stats = &speedo_get_stats; -#ifdef NEW_MULTICAST dev->set_multicast_list = &set_rx_mode; -#endif -#ifdef HAVE_PRIVATE_IOCTL dev->do_ioctl = &speedo_ioctl; -#endif return; } @@ -760,38 +673,31 @@ #define EE_ENB (0x4800 | EE_CS) /* Delay between EEPROM clock transitions. - This is a "nasty" timing loop, but PC compatible machines are defined - to delay an ISA compatible period for the SLOW_DOWN_IO macro. */ -#ifdef _LINUX_DELAY_H + This will actually work with no delay on 33Mhz PCI. */ #define eeprom_delay(nanosec) udelay(1); -#else -#define eeprom_delay(nanosec) do { int _i = 3; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) -#endif /* The EEPROM commands include the alway-set leading bit. */ -#define EE_WRITE_CMD (5 << 6) -#define EE_READ_CMD (6 << 6) -#define EE_ERASE_CMD (7 << 6) +#define EE_WRITE_CMD (5 << addr_len) +#define EE_READ_CMD (6 << addr_len) +#define EE_ERASE_CMD (7 << addr_len) -static int read_eeprom(int ioaddr, int location) +static int read_eeprom(long ioaddr, int location, int addr_len) { - int i; unsigned short retval = 0; int ee_addr = ioaddr + SCBeeprom; int read_cmd = location | EE_READ_CMD; + int i; outw(EE_ENB & ~EE_CS, ee_addr); outw(EE_ENB, ee_addr); /* Shift the read command bits out. */ - for (i = 10; i >= 0; i--) { + for (i = 12; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outw(EE_ENB | dataval, ee_addr); eeprom_delay(100); outw(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(150); - outw(EE_ENB | dataval, ee_addr); /* Finish EEPROM a clock tick. */ - eeprom_delay(250); } outw(EE_ENB, ee_addr); @@ -808,16 +714,11 @@ return retval; } -static int mdio_read(int ioaddr, int phy_id, int location) +static int mdio_read(long ioaddr, int phy_id, int location) { - int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ + int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); do { -#ifdef _LINUX_DELAY_H - udelay(16); -#else - SLOW_DOWN_IO; -#endif val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val); @@ -826,17 +727,12 @@ return val & 0xffff; } -static int mdio_write(int ioaddr, int phy_id, int location, int value) +static int mdio_write(long ioaddr, int phy_id, int location, int value) { - int val, boguscnt = 64*4; /* <64 usec. to complete, typ 27 ticks */ + int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ outl(0x04000000 | (location<<16) | (phy_id<<21) | value, ioaddr + SCBCtrlMDI); do { -#ifdef _LINUX_DELAY_H - udelay(16); -#else - SLOW_DOWN_IO; -#endif val = inl(ioaddr + SCBCtrlMDI); if (--boguscnt < 0) { printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val); @@ -850,24 +746,38 @@ speedo_open(struct device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; #ifdef notdef /* We could reset the chip, but should not need to. */ + /* In fact we MUST NOT, unless we also re-do the init */ outl(0, ioaddr + SCBPort); - for (i = 40; i >= 0; i--) - SLOW_DOWN_IO; /* At least 250ns */ + udelay(10); #endif - if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, - "Intel EtherExpress Pro 10/100 Ethernet", dev)) { - return -EAGAIN; - } + /* This had better be initialized before we initialize the interrupt! */ + sp->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; if (speedo_debug > 1) printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); - MOD_INC_USE_COUNT; +#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us + /* Retrigger negotiation to reset previous errors. */ + if ((sp->phy[0] & 0x8000) == 0) { + int phy_addr = sp->phy[0] & 0x1f ; + /* Use 0x3300 for restarting NWay, other values to force xcvr: + 0x0000 10-HD + 0x0100 10-FD + 0x2000 100-HD + 0x2100 100-FD + */ +#ifdef honor_default_port + mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]); +#else + mdio_write(ioaddr, phy_addr, 0, 0x3300); +#endif + } +#endif /* Load the statistics block address. */ wait_for_cmd_done(ioaddr + SCBCmd); @@ -921,6 +831,7 @@ /* Setup the chip and configure the multicast list. */ sp->mc_setup_frm = NULL; sp->mc_setup_frm_len = 0; + sp->mc_setup_busy = 0; sp->rx_mode = -1; /* Invalid -> always reset the mode. */ set_rx_mode(dev); @@ -928,6 +839,24 @@ printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n", dev->name, inw(ioaddr + SCBStatus)); } + + wait_for_cmd_done(ioaddr + SCBCmd); + outw(CU_DUMPSTATS, ioaddr + SCBCmd); + /* No need to wait for the command unit to accept here. */ + if ((sp->phy[0] & 0x8000) == 0) + mdio_read(ioaddr, sp->phy[0] & 0x1f, 0); + + /* + * Request the IRQ last, after we have set up all data structures. + * It would be bad to get an interrupt before we're ready. + */ + if (request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, + "Intel EtherExpress Pro 10/100 Ethernet", dev)) { + return -EAGAIN; + } + + MOD_INC_USE_COUNT; + /* Set the timer. The timer serves a dual purpose: 1) to monitor the media interface (e.g. link beat) and perhaps switch to an alternate media type @@ -939,8 +868,6 @@ sp->timer.function = &speedo_timer; /* timer handler */ add_timer(&sp->timer); - wait_for_cmd_done(ioaddr + SCBCmd); - outw(CU_DUMPSTATS, ioaddr + SCBCmd); return 0; } @@ -949,24 +876,22 @@ { struct device *dev = (struct device *)data; struct speedo_private *sp = (struct speedo_private *)dev->priv; - int tickssofar = jiffies - sp->last_rx_time; if (speedo_debug > 3) { - int ioaddr = dev->base_addr; - printk(KERN_DEBUG "%s: Media selection tick, status %4.4x.\n", + long ioaddr = dev->base_addr; + printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); } - if (sp->rx_bug) { - if (tickssofar > 2*HZ || sp->rx_mode < 0) { - /* We haven't received a packet in a Long Time. We might have been - bitten by the receiver hang bug. This can be cleared by sending - a set multicast list command. */ - set_rx_mode(dev); - } - /* We must continue to monitor the media. */ - sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */ - add_timer(&sp->timer); + if (sp->rx_mode < 0 || + (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) { + /* We haven't received a packet in a Long Time. We might have been + bitten by the receiver hang bug. This can be cleared by sending + a set multicast list command. */ + set_rx_mode(dev); } + /* We must continue to monitor the media. */ + sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */ + add_timer(&sp->timer); } /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ @@ -978,43 +903,32 @@ int i; sp->cur_rx = 0; - sp->dirty_rx = RX_RING_SIZE - 1; for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; -#ifndef KERNEL_1_2 skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); -#else - skb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC); -#endif sp->rx_skbuff[i] = skb; if (skb == NULL) - break; /* Bad news! */ + break; /* OK. Just initially short of Rx bufs. */ skb->dev = dev; /* Mark as being used by this device. */ - -#if LINUX_VERSION_CODE >= 0x10300 rxf = (struct RxFD *)skb->tail; - skb_reserve(skb, sizeof(struct RxFD)); -#else - /* Save the data in the header region -- it's restored later. */ - rxf = (struct RxFD *)(skb->data - sizeof(struct RxFD)); - memcpy(&sp->saved_skhead[i], rxf, sizeof(struct RxFD)); -#endif sp->rx_ringp[i] = rxf; + skb_reserve(skb, sizeof(struct RxFD)); if (last_rxf) last_rxf->link = virt_to_bus(rxf); last_rxf = rxf; rxf->status = 0x00000001; /* '1' is flag value only. */ rxf->link = 0; /* None yet. */ -#if LINUX_VERSION_CODE < 0x10300 /* This field unused by i82557, we use it as a consistency check. */ - rxf->rx_buf_addr = virt_to_bus(skb->data); +#ifdef final_version + rxf->rx_buf_addr = 0xffffffff; #else rxf->rx_buf_addr = virt_to_bus(skb->tail); #endif rxf->count = 0; rxf->size = PKT_BUF_SZ; } + sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ last_rxf->status = 0xC0000002; /* '2' is flag value only. */ sp->last_rxf = last_rxf; @@ -1023,40 +937,33 @@ static void speedo_tx_timeout(struct device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; - int i; + long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out: status %4.4x " - "command %4.4x.\n", - dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd)); -#ifndef final_version - printk(KERN_WARNING "%s: Tx timeout fill index %d scavenge index %d.\n", - dev->name, sp->cur_tx, sp->dirty_tx); - printk(KERN_WARNING " Tx queue "); - for (i = 0; i < TX_RING_SIZE; i++) - printk(" %8.8x", (int)sp->tx_ring[i].status); - printk(".\n" KERN_WARNING " Rx ring "); - for (i = 0; i < RX_RING_SIZE; i++) - printk(" %8.8x", (int)sp->rx_ringp[i]->status); - printk(".\n"); - -#else - dev->if_port ^= 1; - printk(KERN_WARNING " (Media type switching not yet implemented.)\n"); - /* Do not do 'dev->tbusy = 0;' there -- it is incorrect. */ -#endif + " %4.4x at %d/%d command %8.8x.\n", + dev->name, inw(ioaddr + SCBStatus), inw(ioaddr + SCBCmd), + sp->dirty_tx, sp->cur_tx, + sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status); if ((inw(ioaddr + SCBStatus) & 0x00C0) != 0x0080) { - printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", - dev->name); - outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), - ioaddr + SCBPointer); - outw(CU_START, ioaddr + SCBCmd); + printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", + dev->name); + outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]), + ioaddr + SCBPointer); + outw(CU_START, ioaddr + SCBCmd); } else { - outw(DRVR_INT, ioaddr + SCBCmd); + outw(DRVR_INT, ioaddr + SCBCmd); + } + /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ + if ((sp->phy[0] & 0x8000) == 0) { + int phy_addr = sp->phy[0] & 0x1f; + mdio_write(ioaddr, phy_addr, 0, 0x0400); + mdio_write(ioaddr, phy_addr, 1, 0x0000); + mdio_write(ioaddr, phy_addr, 4, 0x0000); + mdio_write(ioaddr, phy_addr, 0, 0x8000); +#ifdef honor_default_port + mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]); +#endif } - /* Reset the MII transceiver. */ - if ((sp->phy[0] & 0x8000) == 0) - mdio_write(ioaddr, sp->phy[0] & 0x1f, 0, 0x8000); sp->stats.tx_errors++; dev->trans_start = jiffies; return; @@ -1066,7 +973,7 @@ speedo_start_xmit(struct sk_buff *skb, struct device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; int entry; /* Block a timer-based transmit from overlapping. This could better be @@ -1082,7 +989,7 @@ return 1; } speedo_tx_timeout(dev); - return 0; + return 1; } /* Caution: the write order is important here, set the base address @@ -1091,8 +998,8 @@ { /* Prevent interrupts from changing the Tx ring from underneath us. */ unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&sp->lock, flags); + /* Calculate the Tx descriptor entry. */ entry = sp->cur_tx++ % TX_RING_SIZE; @@ -1103,29 +1010,31 @@ sp->tx_ring[entry].link = virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); sp->tx_ring[entry].tx_desc_addr = - virt_to_bus(&sp->tx_ring[entry].tx_buf_addr); + virt_to_bus(&sp->tx_ring[entry].tx_buf_addr0); /* The data region is always in one buffer descriptor, Tx FIFO threshold of 256. */ sp->tx_ring[entry].count = 0x01208000; - sp->tx_ring[entry].tx_buf_addr = virt_to_bus(skb->data); - sp->tx_ring[entry].tx_buf_size = skb->len; + sp->tx_ring[entry].tx_buf_addr0 = virt_to_bus(skb->data); + sp->tx_ring[entry].tx_buf_size0 = skb->len; /* Todo: perhaps leave the interrupt bit set if the Tx queue is more than half full. Argument against: we should be receiving packets and scavenging the queue. Argument for: if so, it shouldn't matter. */ sp->last_cmd->command &= ~(CmdSuspend | CmdIntr); sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; + /* Trigger the command unit resume. */ wait_for_cmd_done(ioaddr + SCBCmd); outw(CU_RESUME, ioaddr + SCBCmd); - restore_flags(flags); + + spin_unlock_irqrestore(&sp->lock, flags); } /* Leave room for set_rx_mode() to fill two entries. */ if (sp->cur_tx - sp->dirty_tx > TX_RING_SIZE - 3) sp->tx_full = 1; else - dev->tbusy = 0; + clear_bit(0, (void*)&dev->tbusy); dev->trans_start = jiffies; @@ -1138,7 +1047,7 @@ { struct device *dev = (struct device *)dev_instance; struct speedo_private *sp; - int ioaddr, boguscnt = max_interrupt_work; + long ioaddr, boguscnt = max_interrupt_work; unsigned short status; #ifndef final_version @@ -1150,11 +1059,9 @@ ioaddr = dev->base_addr; sp = (struct speedo_private *)dev->priv; + spin_lock(&sp->lock); + #ifndef final_version - if (dev->interrupt) { - printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name); - return; - } dev->interrupt = 1; #endif @@ -1174,19 +1081,6 @@ speedo_rx(dev); if (status & 0x1000) { -#ifdef notdef - int i; - printk(KERN_WARNING"%s: The EEPro100 receiver left the ready" - " state -- %4.4x! Index %d (%d).\n", dev->name, status, - sp->cur_rx, sp->cur_rx % RX_RING_SIZE); - printk(KERN_WARNING " Rx ring:\n "); - for (i = 0; i < RX_RING_SIZE; i++) - printk(" %d %8.8x %8.8x %8.8x %d %d.\n", - i, sp->rx_ringp[i]->status, sp->rx_ringp[i]->link, - sp->rx_ringp[i]->rx_buf_addr, sp->rx_ringp[i]->count, - sp->rx_ringp[i]->size); -#endif - if ((status & 0x003c) == 0x0028) /* No more Rx buffers. */ outw(RX_RESUMENR, ioaddr + SCBCmd); else if ((status & 0x003c) == 0x0008) { /* No resources (why?!) */ @@ -1209,14 +1103,15 @@ if (speedo_debug > 5) printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n", entry, status); - if ((status & 0x8000) == 0) + if ((status & StatusComplete) == 0) break; /* It still hasn't been processed. */ /* Free the original skb. */ if (sp->tx_skbuff[entry]) { sp->stats.tx_packets++; /* Count only user packets. */ - dev_kfree_skb(sp->tx_skbuff[entry]); + dev_free_skb(sp->tx_skbuff[entry]); sp->tx_skbuff[entry] = 0; - } + } else if ((sp->tx_ring[entry].status&0x70000) == CmdNOp << 16) + sp->mc_setup_busy = 0; dirty_tx++; } @@ -1233,7 +1128,7 @@ && dirty_tx > sp->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ sp->tx_full = 0; - dev->tbusy = 0; + clear_bit(0, (void*)&dev->tbusy); mark_bh(NET_BH); } @@ -1253,19 +1148,8 @@ printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", dev->name, inw(ioaddr + SCBStatus)); -#ifndef final_version - /* Special code for testing *only*. */ - { - static int stopit = 100; - if (dev->start == 0 && --stopit < 0) { - printk(KERN_ALERT "%s: Emergency stop, interrupt is stuck.\n", - dev->name); - free_irq(irq, dev); - } - } -#endif - dev->interrupt = 0; + spin_unlock(&sp->lock); return; } @@ -1275,150 +1159,104 @@ struct speedo_private *sp = (struct speedo_private *)dev->priv; int entry = sp->cur_rx % RX_RING_SIZE; int status; + int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx; if (speedo_debug > 4) printk(KERN_DEBUG " In speedo_rx().\n"); /* If we own the next entry, it's a new packet. Send it up. */ - while ((status = sp->rx_ringp[entry]->status) & RX_COMPLETE) { + while (sp->rx_ringp[entry] != NULL && + (status = sp->rx_ringp[entry]->status) & RxComplete) { + if (--rx_work_limit < 0) + break; if (speedo_debug > 4) printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status, sp->rx_ringp[entry]->count & 0x3fff); - if (status & 0x0200) { - printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, " - "status %8.8x!\n", dev->name, status); - } else if ( ! (status & 0x2000)) { - /* There was a fatal error. This *should* be impossible. */ - sp->stats.rx_errors++; - printk(KERN_ERR "%s: Anomalous event in speedo_rx(), status %8.8x.\n", - dev->name, status); + if ((status & (RxErrTooBig|RxOK)) != RxOK) { + if (status & RxErrTooBig) + printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, " + "status %8.8x!\n", dev->name, status); + else if ( ! (status & 0x2000)) { + /* There was a fatal error. This *should* be impossible. */ + sp->stats.rx_errors++; + printk(KERN_ERR "%s: Anomalous event in speedo_rx(), " + "status %8.8x.\n", + dev->name, status); + } } else { - /* Malloc up new buffer, compatible with net-2e. */ int pkt_len = sp->rx_ringp[entry]->count & 0x3fff; struct sk_buff *skb; - int rx_in_place = 0; /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ - if (pkt_len > rx_copybreak) { - struct sk_buff *newskb; - char *temp; - - /* Pass up the skb already on the Rx ring. */ - skb = sp->rx_skbuff[entry]; -#ifdef KERNEL_1_2 - temp = skb->data; - if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) - printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match" - " in speedo_rx: %p vs. %p / %p.\n", dev->name, - bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), - temp, skb->data); - /* Get a fresh skbuff to replace the filled one. */ - newskb = alloc_skb(PKT_BUF_SZ, GFP_ATOMIC); -#else - temp = skb_put(skb, pkt_len); - if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) - printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match" - " in speedo_rx: %8.8x vs. %p / %p.\n", dev->name, - sp->rx_ringp[entry]->rx_buf_addr, skb->head, temp); - /* Get a fresh skbuff to replace the filled one. */ - newskb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); -#endif - if (newskb) { - struct RxFD *rxf; - rx_in_place = 1; - sp->rx_skbuff[entry] = newskb; - newskb->dev = dev; -#ifdef KERNEL_1_2 - /* Restore the data in the old header region. */ - memcpy(skb->data - sizeof(struct RxFD), - &sp->saved_skhead[entry], sizeof(struct RxFD)); - /* Save the data in this header region. */ - rxf = (struct RxFD *)(newskb->data - sizeof(struct RxFD)); - sp->rx_ringp[entry] = rxf; - memcpy(&sp->saved_skhead[entry], rxf, sizeof(struct RxFD)); - rxf->rx_buf_addr = virt_to_bus(newskb->data); -#else - rxf = sp->rx_ringp[entry] = (struct RxFD *)newskb->tail; - skb_reserve(newskb, sizeof(struct RxFD)); - /* Unused by i82557, consistency check only. */ - rxf->rx_buf_addr = virt_to_bus(newskb->tail); -#endif - rxf->status = 0x00000001; - } else /* No memory, drop the packet. */ - skb = 0; - } else -#ifdef KERNEL_1_2 - skb = alloc_skb(pkt_len, GFP_ATOMIC); -#else - skb = dev_alloc_skb(pkt_len + 2); -#endif - if (skb == NULL) { - int i; - printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", dev->name); - /* Check that at least two ring entries are free. - If not, free one and mark stats->rx_dropped++. */ - /* ToDo: This is not correct!!!! We should count the number - of linked-in Rx buffer to very that we have at least two - remaining. */ - for (i = 0; i < RX_RING_SIZE; i++) - if (! ((sp->rx_ringp[(entry+i) % RX_RING_SIZE]->status) - & RX_COMPLETE)) - break; - - if (i > RX_RING_SIZE -2) { - sp->stats.rx_dropped++; - sp->rx_ringp[entry]->status = 0; - sp->cur_rx++; - } - break; - } - skb->dev = dev; -#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 (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { + skb->dev = dev; + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + /* 'skb_put()' points to the start of sk_buff data area. */ +#if 1 || USE_IP_CSUM /* 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); + eth_copy_and_sum(skb, + bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), + pkt_len, 0); + skb_put(skb, pkt_len); #else memcpy(skb_put(skb, pkt_len), bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len); #endif + } else { + void *temp; + /* Pass up the already-filled skbuff. */ + skb = sp->rx_skbuff[entry]; + if (skb == NULL) { + printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n", + dev->name); + break; + } + sp->rx_skbuff[entry] = NULL; + temp = skb_put(skb, pkt_len); + if (bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr) != temp) + printk(KERN_ERR "%s: Rx consistency error -- the skbuff " + "addresses do not match in speedo_rx: %p vs. %p " + "/ %p.\n", dev->name, + bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), + skb->head, temp); + sp->rx_ringp[entry] = NULL; } skb->protocol = eth_type_trans(skb, dev); -#else -#ifdef KERNEL_1_3 -#warning This code has only been tested with later 1.3.* kernels. - skb->len = pkt_len; - memcpy(skb->data, bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), - pkt_len); - /* Needed for 1.3.*. */ - skb->protocol = eth_type_trans(skb, dev); -#else /* KERNEL_1_2 */ - skb->len = pkt_len; - if (! rx_in_place) { - memcpy(skb->data, - bus_to_virt(sp->rx_ringp[entry]->rx_buf_addr), pkt_len); - } -#endif -#endif netif_rx(skb); sp->stats.rx_packets++; } + entry = (++sp->cur_rx) % RX_RING_SIZE; + } - /* ToDo: This is better than before, but should be checked. */ - { - struct RxFD *rxf = sp->rx_ringp[entry]; - rxf->status = 0xC0000003; /* '3' for verification only */ - rxf->link = 0; /* None yet. */ - rxf->count = 0; - rxf->size = PKT_BUF_SZ; - sp->last_rxf->link = virt_to_bus(rxf); - sp->last_rxf->status &= ~0xC0000000; - sp->last_rxf = rxf; - entry = (++sp->cur_rx) % RX_RING_SIZE; + /* Refill the Rx ring buffers. */ + for (; sp->dirty_rx < sp->cur_rx; sp->dirty_rx++) { + struct RxFD *rxf; + entry = sp->dirty_rx % RX_RING_SIZE; + if (sp->rx_skbuff[entry] == NULL) { + struct sk_buff *skb; + /* Get a fresh skbuff to replace the consumed one. */ + skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); + sp->rx_skbuff[entry] = skb; + if (skb == NULL) { + sp->rx_ringp[entry] = NULL; + break; /* Better luck next time! */ + } + rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail; + skb->dev = dev; + skb_reserve(skb, sizeof(struct RxFD)); + rxf->rx_buf_addr = virt_to_bus(skb->tail); + } else { + rxf = sp->rx_ringp[entry]; } + rxf->status = 0xC0000001; /* '1' for driver use only. */ + rxf->link = 0; /* None yet. */ + rxf->count = 0; + rxf->size = PKT_BUF_SZ; + sp->last_rxf->link = virt_to_bus(rxf); + sp->last_rxf->status &= ~0xC0000000; + sp->last_rxf = rxf; } sp->last_rx_time = jiffies; @@ -1428,7 +1266,7 @@ static int speedo_close(struct device *dev) { - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; struct speedo_private *sp = (struct speedo_private *)dev->priv; int i; @@ -1454,7 +1292,7 @@ sp->rx_skbuff[i] = 0; /* Clear the Rx descriptors. */ if (skb) - dev_kfree_skb(skb); + dev_free_skb(skb); } for (i = 0; i < TX_RING_SIZE; i++) { @@ -1462,7 +1300,7 @@ sp->tx_skbuff[i] = 0; /* Clear the Tx descriptors. */ if (skb) - dev_kfree_skb(skb); + dev_free_skb(skb); } if (sp->mc_setup_frm) { kfree(sp->mc_setup_frm); @@ -1507,7 +1345,7 @@ speedo_get_stats(struct device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; if (sp->lstats.done_marker == 0xA007) { /* Previous dump finished */ sp->stats.tx_aborted_errors += sp->lstats.tx_coll16_errs; @@ -1530,11 +1368,10 @@ return &sp->stats; } -#ifdef HAVE_PRIVATE_IOCTL static int speedo_ioctl(struct device *dev, struct ifreq *rq, int cmd) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; int phy = sp->phy[0] & 0x1f; @@ -1545,7 +1382,7 @@ data[3] = mdio_read(ioaddr, data[0], data[1]); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!capable(CAP_NET_ADMIN)) + if (!suser()) return -EPERM; mdio_write(ioaddr, data[0], data[1], data[2]); return 0; @@ -1553,7 +1390,6 @@ return -EOPNOTSUPP; } } -#endif /* HAVE_PRIVATE_IOCTL */ /* Set or clear the multicast filter for this adaptor. This is very ugly with Intel chips -- we usually have to execute an @@ -1568,14 +1404,16 @@ set_rx_mode(struct device *dev) { struct speedo_private *sp = (struct speedo_private *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; + struct descriptor *last_cmd; char new_rx_mode; unsigned long flags; int entry, i; if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ new_rx_mode = 3; - } else if (dev->flags & IFF_ALLMULTI) { + } else if ((dev->flags & IFF_ALLMULTI) || + dev->mc_count > multicast_filter_limit) { new_rx_mode = 1; } else new_rx_mode = 0; @@ -1588,57 +1426,54 @@ } if (new_rx_mode != sp->rx_mode) { - /* We must change the configuration. Construct a CmdConfig frame. */ - memcpy(sp->config_cmd_data, basic_config_cmd,sizeof(basic_config_cmd)); - sp->config_cmd_data[1] = (txfifo << 4) | rxfifo; - sp->config_cmd_data[4] = rxdmacount; - sp->config_cmd_data[5] = txdmacount + 0x80; - sp->config_cmd_data[15] = (new_rx_mode & 2) ? 0x49 : 0x48; - sp->config_cmd_data[19] = sp->full_duplex ? 0xC0 : 0x80; - sp->config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05; + u8 *config_cmd_data; + + spin_lock_irqsave(&sp->lock, flags); + entry = sp->cur_tx++ % TX_RING_SIZE; + last_cmd = sp->last_cmd; + sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; + + sp->tx_skbuff[entry] = 0; /* Redundant. */ + sp->tx_ring[entry].status = (CmdSuspend | CmdConfigure) << 16; + sp->tx_ring[entry].link = + virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]); + config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr; + /* Construct a full CmdConfig frame. */ + memcpy(config_cmd_data, i82558_config_cmd, sizeof(i82558_config_cmd)); + config_cmd_data[1] = (txfifo << 4) | rxfifo; + config_cmd_data[4] = rxdmacount; + config_cmd_data[5] = txdmacount + 0x80; + config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0; + config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0; + config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05; if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */ - sp->config_cmd_data[15] |= 0x80; - sp->config_cmd_data[8] = 0; + config_cmd_data[15] |= 0x80; + config_cmd_data[8] = 0; } - save_flags(flags); - cli(); - /* Fill the "real" tx_ring frame with a no-op and point it to us. */ - entry = sp->cur_tx++ % TX_RING_SIZE; - sp->tx_skbuff[entry] = 0; /* Nothing to free. */ - sp->tx_ring[entry].status = CmdNOp << 16; - sp->tx_ring[entry].link = virt_to_bus(&sp->config_cmd); - sp->config_cmd.status = 0; - sp->config_cmd.command = CmdSuspend | CmdConfigure; - sp->config_cmd.link = - virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE])); - sp->last_cmd->command &= ~CmdSuspend; - /* Immediately trigger the command unit resume. */ + /* Trigger the command unit resume. */ + last_cmd->command &= ~CmdSuspend; + wait_for_cmd_done(ioaddr + SCBCmd); outw(CU_RESUME, ioaddr + SCBCmd); - sp->last_cmd = &sp->config_cmd; - restore_flags(flags); - if (speedo_debug > 5) { - int i; - printk(KERN_DEBUG " CmdConfig frame in entry %d.\n", entry); - for(i = 0; i < 32; i++) - printk(" %2.2x", ((unsigned char *)&sp->config_cmd)[i]); - printk(".\n"); - } + + spin_unlock_irqrestore(&sp->lock, flags); } - if (new_rx_mode == 0 && dev->mc_count < 3) { - /* The simple case of 0-2 multicast list entries occurs often, and + if (new_rx_mode == 0 && dev->mc_count < 4) { + /* The simple case of 0-3 multicast list entries occurs often, and fits within one tx_ring[] entry. */ - u16 *setup_params, *eaddrs; struct dev_mc_list *mclist; + u16 *setup_params, *eaddrs; - save_flags(flags); - cli(); + spin_lock_irqsave(&sp->lock, flags); entry = sp->cur_tx++ % TX_RING_SIZE; + last_cmd = sp->last_cmd; + sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; + sp->tx_skbuff[entry] = 0; sp->tx_ring[entry].status = (CmdSuspend | CmdMulticastList) << 16; sp->tx_ring[entry].link = - virt_to_bus(&sp->tx_ring[sp->cur_tx % TX_RING_SIZE]); + virt_to_bus(&sp->tx_ring[(entry + 1) % TX_RING_SIZE]); sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */ setup_params = (u16 *)&sp->tx_ring[entry].tx_desc_addr; *setup_params++ = dev->mc_count*6; @@ -1651,36 +1486,42 @@ *setup_params++ = *eaddrs++; } - sp->last_cmd->command &= ~CmdSuspend; + last_cmd->command &= ~CmdSuspend; + /* Immediately trigger the command unit resume. */ wait_for_cmd_done(ioaddr + SCBCmd); outw(CU_RESUME, ioaddr + SCBCmd); - sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - restore_flags(flags); + + spin_unlock_irqrestore(&sp->lock, flags); } else if (new_rx_mode == 0) { - /* This does not work correctly, but why not? */ struct dev_mc_list *mclist; - u16 *eaddrs; + u16 *setup_params, *eaddrs; struct descriptor *mc_setup_frm = sp->mc_setup_frm; - u16 *setup_params = (u16 *)mc_setup_frm->params; int i; if (sp->mc_setup_frm_len < 10 + dev->mc_count*6 || sp->mc_setup_frm == NULL) { - /* Allocate a new frame, 10bytes + addrs, with a few - extra entries for growth. */ + /* Allocate a full setup frame, 10bytes + . */ if (sp->mc_setup_frm) kfree(sp->mc_setup_frm); - sp->mc_setup_frm_len = 10 + dev->mc_count*6 + 24; + sp->mc_setup_busy = 0; + sp->mc_setup_frm_len = 10 + multicast_filter_limit*6; sp->mc_setup_frm = kmalloc(sp->mc_setup_frm_len, GFP_ATOMIC); if (sp->mc_setup_frm == NULL) { - printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", dev->name); + printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", + dev->name); sp->rx_mode = -1; /* We failed, try again. */ return; } } + /* If we are busy, someone might be quickly adding to the MC list. + Try again later when the list changes stop. */ + if (sp->mc_setup_busy) { + sp->rx_mode = -1; + return; + } mc_setup_frm = sp->mc_setup_frm; - /* Construct the new setup frame. */ + /* Fill the setup frame. */ if (speedo_debug > 1) printk(KERN_DEBUG "%s: Constructing a setup frame at %p, " "%d bytes.\n", @@ -1688,7 +1529,7 @@ mc_setup_frm->status = 0; mc_setup_frm->command = CmdSuspend | CmdIntr | CmdMulticastList; /* Link set below. */ - setup_params = (u16 *)mc_setup_frm->params; + setup_params = (u16 *)&mc_setup_frm->params; *setup_params++ = dev->mc_count*6; /* Fill in the multicast addresses. */ for (i = 0, mclist = dev->mc_list; i < dev->mc_count; @@ -1700,13 +1541,12 @@ } /* Disable interrupts while playing with the Tx Cmd list. */ - save_flags(flags); - cli(); - entry = sp->cur_tx++ % TX_RING_SIZE; + spin_lock_irqsave(&sp->lock, flags); - if (speedo_debug > 5) - printk(" CmdMCSetup frame length %d in entry %d.\n", - dev->mc_count, entry); + entry = sp->cur_tx++ % TX_RING_SIZE; + last_cmd = sp->last_cmd; + sp->last_cmd = mc_setup_frm; + sp->mc_setup_busy++; /* Change the command to a NoOp, pointing to the CmdMulti command. */ sp->tx_skbuff[entry] = 0; @@ -1715,41 +1555,25 @@ /* Set the link in the setup frame. */ mc_setup_frm->link = - virt_to_bus(&(sp->tx_ring[sp->cur_tx % TX_RING_SIZE])); + virt_to_bus(&(sp->tx_ring[(entry+1) % TX_RING_SIZE])); + + last_cmd->command &= ~CmdSuspend; - sp->last_cmd->command &= ~CmdSuspend; /* Immediately trigger the command unit resume. */ wait_for_cmd_done(ioaddr + SCBCmd); outw(CU_RESUME, ioaddr + SCBCmd); - sp->last_cmd = mc_setup_frm; - restore_flags(flags); - if (speedo_debug > 1) - printk(KERN_DEBUG "%s: Last command at %p is %4.4x.\n", - dev->name, sp->last_cmd, sp->last_cmd->command); + + spin_unlock_irqrestore(&sp->lock, flags); + + if (speedo_debug > 5) + printk(" CmdMCSetup frame length %d in entry %d.\n", + dev->mc_count, entry); } sp->rx_mode = new_rx_mode; } #ifdef MODULE -#if (LINUX_VERSION_CODE < VERSION(1,3,38)) /* 1.3.38 and later */ -char kernel_version[] = UTS_RELEASE; -#endif - -#if LINUX_VERSION_CODE > 0x20118 -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("Intel i82557/i82558 EtherExpressPro driver"); -MODULE_PARM(debug, "i"); -MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); -MODULE_PARM(congenb, "i"); -MODULE_PARM(txfifo, "i"); -MODULE_PARM(rxfifo, "i"); -MODULE_PARM(txdmacount, "i"); -MODULE_PARM(rxdmacount, "i"); -MODULE_PARM(rx_copybreak, "i"); -MODULE_PARM(max_interrupt_work, "i"); -#endif int init_module(void) @@ -1796,7 +1620,8 @@ /* * Local variables: - * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c" + * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" + * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" * c-indent-level: 4 * c-basic-offset: 4 * tab-width: 4 diff -u --recursive --new-file v2.1.125/linux/drivers/net/eth16i.c linux/drivers/net/eth16i.c --- v2.1.125/linux/drivers/net/eth16i.c Thu Feb 12 20:56:08 1998 +++ linux/drivers/net/eth16i.c Fri Oct 9 11:56:59 1998 @@ -1,122 +1,207 @@ /* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux - - Written 1994-95 by Mika Kuoppala - - Copyright (C) 1994, 1995 by Mika Kuoppala - Based on skeleton.c and at1700.c by Donald Becker + + Written 1994-1998 by Mika Kuoppala + + Copyright (C) 1994-1998 by Mika Kuoppala + Based on skeleton.c and heavily on at1700.c by Donald Becker This software may be used and distributed according to the terms of the GNU Public Licence, incorporated herein by reference. - The author may be reached as miku@elt.icl.fi + The author may be reached as miku@iki.fi This driver supports following cards : - ICL EtherTeam 16i - - ICL EtherTeam 32 EISA + - ICL EtherTeam 32 EISA + (Uses true 32 bit transfers rather than 16i compability mode) + + Example Module usage: + insmod eth16i.o ioaddr=0x2a0 mediatype=bnc + + mediatype can be one of the following: bnc,tp,dix,auto,eprom + 'auto' will try to autoprobe mediatype. + 'eprom' will use whatever type defined in eprom. + + I have benchmarked driver with PII/300Mhz as a ftp client + and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec. + Sources: - skeleton.c a sample network driver core for linux, written by Donald Becker - - at1700.c a driver for Allied Telesis AT1700, written + - at1700.c a driver for Allied Telesis AT1700, written by Donald Becker. - e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i written by Markku Viima - The Fujitsu MB86965 databook. - - Valuable assistance from: - Markku Viima (ICL) - Ari Valve (ICL) + + Author thanks following persons due to their valueble assistance: + Markku Viima (ICL) + Ari Valve (ICL) + Donald Becker + Kurt Huwig Revision history: Version Date Description - - 0.01 15.12-94 Initial version (card detection) + + 0.01 15.12-94 Initial version (card detection) 0.02 23.01-95 Interrupt is now hooked correctly 0.03 01.02-95 Rewrote initialization part 0.04 07.02-95 Base skeleton done... - Made a few changes to signature checking - to make it a bit reliable. - - fixed bug in tx_buf mapping - - fixed bug in initialization (DLC_EN - wasn't enabled when initialization - was done.) - 0.05 08.02-95 If there were more than one packet to send, - transmit was jammed due to invalid - register write...now fixed - 0.06 19.02-95 Rewrote interrupt handling + Made a few changes to signature checking + to make it a bit reliable. + - fixed bug in tx_buf mapping + - fixed bug in initialization (DLC_EN + wasn't enabled when initialization + was done.) + 0.05 08.02-95 If there were more than one packet to send, + transmit was jammed due to invalid + register write...now fixed + 0.06 19.02-95 Rewrote interrupt handling 0.07 13.04-95 Wrote EEPROM read routines Card configuration now set according to - data read from EEPROM + data read from EEPROM 0.08 23.06-95 Wrote part that tries to probe used interface port if AUTO is selected - 0.09 01.09-95 Added module support - - 0.10 04.09-95 Fixed receive packet allocation to work - with kernels > 1.3.x + 0.09 01.09-95 Added module support + + 0.10 04.09-95 Fixed receive packet allocation to work + with kernels > 1.3.x + + 0.20 20.09-95 Added support for EtherTeam32 EISA - 0.20 20.09-95 Added support for EtherTeam32 EISA - - 0.21 17.10-95 Removed the unnecessary extern + 0.21 17.10-95 Removed the unnecessary extern init_etherdev() declaration. Some other cleanups. + + 0.22 22.02-96 Receive buffer was not flushed + correctly when faulty packet was + received. Now fixed. + + 0.23 26.02-96 Made resetting the adapter + more reliable. + + 0.24 27.02-96 Rewrote faulty packet handling in eth16i_rx + + 0.25 22.05-96 kfree() was missing from cleanup_module. + + 0.26 11.06-96 Sometimes card was not found by + check_signature(). Now made more reliable. + + 0.27 23.06-96 Oops. 16 consecutive collisions halted + adapter. Now will try to retransmit + MAX_COL_16 times before finally giving up. + + 0.28 28.10-97 Added dev_id parameter (NULL) for free_irq + + 0.29 29.10-97 Multiple card support for module users + + 0.30 30.10-97 Fixed irq allocation bug. + (request_irq moved from probe to open) + + 0.30a 21.08-98 Card detection made more relaxed. Driver + had problems with some TCP/IP-PROM boots + to find the card. Suggested by + Kurt Huwig + + 0.31 28.08-98 Media interface port can now be selected + with module parameters or kernel + boot parameters. + + 0.32 31.08-98 IRQ was never freed if open/close + pair wasn't called. Now fixed. + + 0.33 10.09-98 When eth16i_open() was called after + eth16i_close() chip never recovered. + Now more shallow reset is made on + close. + Bugs: - In some cases the interface autoprobing code doesn't find - the correct interface type. In this case you can - manually choose the interface type in DOS with E16IC.EXE which is + In some cases the media interface autoprobing code doesn't find + the correct interface type. In this case you can + manually choose the interface type in DOS with E16IC.EXE which is configuration software for EtherTeam16i and EtherTeam32 cards. + This is also true for IRQ setting. You cannot use module + parameter to configure IRQ of the card (yet). To do: - Real multicast support + - Rewrite the media interface autoprobing code. Its _horrible_ ! + - Possibly merge all the MB86965 specific code to external + module for use by eth16.c and Donald's at1700.c + - IRQ configuration with module parameter. I will do + this when i will get enough info about setting + irq without configuration utility. */ -static char *version = - "eth16i.c: v0.21 17-10-95 Mika Kuoppala (miku@elt.icl.fi)\n"; +static char *version = + "eth16i.c: v0.33 10-09-98 Mika Kuoppala (miku@iki.fi)\n"; #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include -#include #include #include #include -#include -#include -#include +#include +#include +#include #include -#include + +#ifndef LINUX_VERSION_CODE +#include +#endif + +#if LINUX_VERSION_CODE >= 0x20123 +#include +#else +#define __init +#define __initdata +#define __initfunc(x) x +#endif + +#if LINUX_VERSION_CODE < 0x20138 +#define test_and_set_bit(val,addr) set_bit(val,addr) +#endif + +#if LINUX_VERSION_CODE < 0x020100 +typedef struct enet_statistics eth16i_stats_type; +#else +typedef struct net_device_stats eth16i_stats_type; +#endif /* Few macros */ -#define BIT(a) ( (1 << (a)) ) -#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr))) +#define BIT(a) ( (1 << (a)) ) +#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr))) #define BITCLR(ioaddr, bnum) ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr))) /* This is the I/O address space for Etherteam 16i adapter. */ -#define ETH16I_IO_EXTENT 32 +#define ETH16I_IO_EXTENT 32 /* Ticks before deciding that transmit has timed out */ -#define TIMEOUT_TICKS 30 +#define TX_TIMEOUT (400*HZ/1000) /* Maximum loop count when receiving packets */ -#define MAX_RX_LOOP 40 +#define MAX_RX_LOOP 20 /* Some interrupt masks */ -#define ETH16I_INTR_ON 0x8f82 +#define ETH16I_INTR_ON 0xef8a /* Higher is receive mask */ #define ETH16I_INTR_OFF 0x0000 - + /* Buffers header status byte meanings */ #define PKT_GOOD BIT(5) #define PKT_GOOD_RMT BIT(4) @@ -131,6 +216,7 @@ #define NET_BUSY BIT(6) #define TX_PKT_RCD BIT(5) #define CR_LOST BIT(4) +#define TX_JABBER_ERR BIT(3) #define COLLISION BIT(2) #define COLLISIONS_16 BIT(1) @@ -142,7 +228,7 @@ #define ALIGN_ERR BIT(2) #define CRC_ERR BIT(1) #define RX_BUF_OVERFLOW BIT(0) - + /* Transmit Interrupt Enable Register (DLCR2) */ #define TX_INTR_REG 2 #define TX_INTR_DONE BIT(7) @@ -181,18 +267,18 @@ #define SRAM_CYCLE_TIME_100NS BIT(6) #define SYSTEM_BUS_WIDTH_8 BIT(5) /* 1 = 8bit, 0 = 16bit */ #define BUFFER_WIDTH_8 BIT(4) /* 1 = 8bit, 0 = 16bit */ -#define TBS1 BIT(3) +#define TBS1 BIT(3) #define TBS0 BIT(2) -#define MBS1 BIT(1) /* 00=8kb, 01=16kb */ -#define MBS0 BIT(0) /* 10=32kb, 11=64kb */ +#define SRAM_BS1 BIT(1) /* 00=8kb, 01=16kb */ +#define SRAM_BS0 BIT(0) /* 10=32kb, 11=64kb */ -#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */ -#define ETH16I_TX_BUF_SIZE 2 /* 2 = 8kb, 3 = 16kb */ -#endif -#define TX_BUF_1x2048 0 -#define TX_BUF_2x2048 1 -#define TX_BUF_2x4098 2 -#define TX_BUF_2x8192 3 +#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */ +#define ETH16I_TX_BUF_SIZE 3 /* 2 = 8kb, 3 = 16kb */ +#endif +#define TX_BUF_1x2048 0 +#define TX_BUF_2x2048 1 +#define TX_BUF_2x4098 2 +#define TX_BUF_2x8192 3 /* Configuration Register 1 (DLCR7) */ #define CONFIG_REG_1 7 @@ -212,18 +298,21 @@ #define HASH_TABLE_RB 1 /* Buffer memory ports */ -#define BUFFER_MEM_PORT_LB 8 -#define DATAPORT BUFFER_MEM_PORT_LB -#define BUFFER_MEM_PORT_HB 9 +#define BUFFER_MEM_PORT_LB 8 +#define DATAPORT BUFFER_MEM_PORT_LB +#define BUFFER_MEM_PORT_HB 9 /* 16 Collision control register (BMPR11) */ #define COL_16_REG 11 #define HALT_ON_16 0x00 #define RETRANS_AND_HALT_ON_16 0x02 +/* Maximum number of attempts to send after 16 concecutive collisions */ +#define MAX_COL_16 10 + /* DMA Burst and Transceiver Mode Register (BMPR13) */ #define TRANSCEIVER_MODE_REG 13 -#define TRANSCEIVER_MODE_RB 2 +#define TRANSCEIVER_MODE_RB 2 #define IO_BASE_UNLOCK BIT(7) #define LOWER_SQUELCH_TRESH BIT(6) #define LINK_TEST_DISABLE BIT(5) @@ -232,9 +321,8 @@ /* Filter Self Receive Register (BMPR14) */ #define FILTER_SELF_RX_REG 14 -#define SKIP_RECEIVE_PACKET BIT(2) +#define SKIP_RX_PACKET BIT(2) #define FILTER_SELF_RECEIVE BIT(0) -#define RX_BUF_SKIP_PACKET SKIP_RECEIVE_PACKET | FILTER_SELF_RECEIVE /* EEPROM Control Register (BMPR 16) */ #define EEPROM_CTRL_REG 16 @@ -254,19 +342,20 @@ #define EEPROM_READ 0x80 /* NMC93CSx6 EEPROM Addresses */ -#define E_NODEID_0 0x02 -#define E_NODEID_1 0x03 -#define E_NODEID_2 0x04 -#define E_PORT_SELECT 0x14 - #define E_PORT_BNC 0 - #define E_PORT_DIX 1 - #define E_PORT_TP 2 - #define E_PORT_AUTO 3 -#define E_PRODUCT_CFG 0x30 - +#define E_NODEID_0 0x02 +#define E_NODEID_1 0x03 +#define E_NODEID_2 0x04 +#define E_PORT_SELECT 0x14 + #define E_PORT_BNC 0x00 + #define E_PORT_DIX 0x01 + #define E_PORT_TP 0x02 + #define E_PORT_AUTO 0x03 + #define E_PORT_FROM_EPROM 0x04 +#define E_PRODUCT_CFG 0x30 + /* Macro to slow down io between EEPROM clock transitions */ -#define eeprom_slow_io() udelay(100) /* FIXME: smaller but right value here */ +#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0) /* Jumperless Configuration Register (BMPR19) */ #define JUMPERLESS_CONFIG 19 @@ -277,31 +366,24 @@ #define RESET ID_ROM_0 /* This is the I/O address list to be probed when seeking the card */ -static unsigned int eth16i_portlist[] __initdata = { - 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 -}; +static unsigned int eth16i_portlist[] = + { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 }; -static unsigned int eth32i_portlist[] __initdata = { - 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, - 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 -}; +static unsigned int eth32i_portlist[] = + { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000, + 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 }; /* This is the Interrupt lookup table for Eth16i card */ -static unsigned int eth16i_irqmap[] __initdata = { - 9, 10, 5, 15 -}; +static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 }; +#define NUM_OF_ISA_IRQS 4 /* This is the Interrupt lookup table for Eth32i card */ -static unsigned int eth32i_irqmap[] __initdata = { - 3, 5, 7, 9, 10, 11, 12, 15 -}; - +static unsigned int eth32i_irqmap[] = { 3, 5, 7, 9, 10, 11, 12, 15, 0 }; #define EISA_IRQ_REG 0xc89 +#define NUM_OF_EISA_IRQS 8 -static unsigned int eth16i_tx_buf_map[] = { - 2048, 2048, 4096, 8192 -}; -unsigned int boot = 1; +static unsigned int eth16i_tx_buf_map[] = { 2048, 2048, 4096, 8192 }; +static unsigned int boot = 1; /* Use 0 for production, 1 for verification, >2 for debug */ #ifndef ETH16I_DEBUG @@ -310,60 +392,76 @@ static unsigned int eth16i_debug = ETH16I_DEBUG; /* Information for each board */ -struct eth16i_local -{ - struct net_device_stats stats; - unsigned int tx_started:1; - unsigned char tx_queue; /* Number of packets in transmit buffer */ - unsigned short tx_queue_len; - unsigned int tx_buf_size; - unsigned long open_time; + +struct eth16i_local { + eth16i_stats_type stats; + unsigned char tx_started; + unsigned char tx_buf_busy; + unsigned short tx_queue; /* Number of packets in transmit buffer */ + unsigned short tx_queue_len; + unsigned int tx_buf_size; + unsigned long open_time; + unsigned long tx_buffered_packets; + unsigned long col_16; }; /* Function prototypes */ -extern int eth16i_probe(struct device *dev); +extern int eth16i_probe(struct device *dev); + +static int eth16i_probe1(struct device *dev, int ioaddr); +static int eth16i_check_signature(int ioaddr); +static int eth16i_probe_port(int ioaddr); +static void eth16i_set_port(int ioaddr, int porttype); +static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l); +static int eth16i_receive_probe_packet(int ioaddr); +static int eth16i_get_irq(int ioaddr); +static int eth16i_read_eeprom(int ioaddr, int offset); +static int eth16i_read_eeprom_word(int ioaddr); +static void eth16i_eeprom_cmd(int ioaddr, unsigned char command); +static int eth16i_open(struct device *dev); +static int eth16i_close(struct device *dev); +static int eth16i_tx(struct sk_buff *skb, struct device *dev); +static void eth16i_rx(struct device *dev); +static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void eth16i_reset(struct device *dev); +static void eth16i_skip_packet(struct device *dev); +static void eth16i_multicast(struct device *dev); +static void eth16i_select_regbank(unsigned char regbank, int ioaddr); +static void eth16i_initialize(struct device *dev); + +#if 0 +static int eth16i_set_irq(struct device *dev); +#endif + +#ifdef MODULE +static ushort eth16i_parse_mediatype(const char* s); +#endif -static int eth16i_probe1(struct device *dev, short ioaddr); -static int eth16i_check_signature(short ioaddr); -static int eth16i_probe_port(short ioaddr); -static void eth16i_set_port(short ioaddr, int porttype); -static int eth16i_send_probe_packet(short ioaddr, unsigned char *b, int l); -static int eth16i_receive_probe_packet(short ioaddr); -static int eth16i_get_irq(short ioaddr); -static int eth16i_read_eeprom(int ioaddr, int offset); -static int eth16i_read_eeprom_word(int ioaddr); -static void eth16i_eeprom_cmd(int ioaddr, unsigned char command); -static int eth16i_open(struct device *dev); -static int eth16i_close(struct device *dev); -static int eth16i_tx(struct sk_buff *skb, struct device *dev); -static void eth16i_rx(struct device *dev); -static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void eth16i_multicast(struct device *dev); -static void eth16i_select_regbank(unsigned char regbank, short ioaddr); -static void eth16i_initialize(struct device *dev); -static struct net_device_stats *eth16i_get_stats(struct device *dev); +static struct enet_statistics *eth16i_get_stats(struct device *dev); static char *cardname = "ICL EtherTeam 16i/32"; -#ifdef HAVE_DEVLIST +#ifdef HAVE_DEVLIST + /* Support for alternate probe manager */ -/struct netdev_entry eth16i_drv = - {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list}; +/struct netdev_entry eth16i_drv = + {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list}; #else /* Not HAVE_DEVLIST */ + __initfunc(int eth16i_probe(struct device *dev)) { int i; int ioaddr; int base_addr = dev ? dev->base_addr : 0; + + if(eth16i_debug > 4) + printk(KERN_DEBUG "Probing started for %s\n", cardname); - if(eth16i_debug > 4) - printk("Probing started for %s\n", cardname); - - if(base_addr > 0x1ff) /* Check only single location */ + if(base_addr > 0x1ff) /* Check only single location */ return eth16i_probe1(dev, base_addr); - else if(base_addr != 0) /* Don't probe at all */ + else if(base_addr != 0) /* Don't probe at all */ return ENXIO; /* Seek card from the ISA io address space */ @@ -377,88 +475,107 @@ /* Seek card from the EISA io address space */ for(i = 0; (ioaddr = eth32i_portlist[i]) ; i++) { if(check_region(ioaddr, ETH16I_IO_EXTENT)) - continue; + continue; if(eth16i_probe1(dev, ioaddr) == 0) - return 0; - } + return 0; + } return ENODEV; } -#endif /* Not HAVE_DEVLIST */ +#endif /* Not HAVE_DEVLIST */ -__initfunc(static int eth16i_probe1(struct device *dev, short ioaddr)) +__initfunc(static int eth16i_probe1(struct device *dev, int ioaddr)) { static unsigned version_printed = 0; - unsigned int irq = 0; - boot = 1; /* To inform initialization that we are in boot probe */ + boot = 1; /* To inform initilization that we are in boot probe */ /* - The MB86985 chip has on register which holds information in which - io address the chip lies. First read this register and compare - it to our current io address and if match then this could - be our chip. - */ + The MB86985 chip has on register which holds information in which + io address the chip lies. First read this register and compare + it to our current io address and if match then this could + be our chip. + */ if(ioaddr < 0x1000) { - if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] != ioaddr) + + if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)] + != ioaddr) return -ENODEV; } /* Now we will go a bit deeper and try to find the chip's signature */ - if(eth16i_check_signature(ioaddr) != 0) /* Can we find the signature here */ + if(eth16i_check_signature(ioaddr) != 0) return -ENODEV; - /* - Now it seems that we have found an ethernet chip in this particular - ioaddr. The MB86985 chip has this feature, that when you read a - certain register it will increase its io base address to next - configurable slot. Now when we have found the chip, first thing is - to make sure that the chip's ioaddr will hold still here. - */ + /* + Now it seems that we have found a ethernet chip in this particular + ioaddr. The MB86985 chip has this feature, that when you read a + certain register it will increase it's io base address to next + configurable slot. Now when we have found the chip, first thing is + to make sure that the chip's ioaddr will hold still here. + */ eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); outb(0x00, ioaddr + TRANSCEIVER_MODE_REG); - outb(0x00, ioaddr + RESET); /* Will reset some parts of chip */ - BITSET(ioaddr + CONFIG_REG_0, BIT(7)); /* This will disable the data link */ + outb(0x00, ioaddr + RESET); /* Reset some parts of chip */ + BITSET(ioaddr + CONFIG_REG_0, BIT(7)); /* Disable the data link */ if(dev == NULL) - dev = init_etherdev(0, sizeof(struct eth16i_local)); + dev = init_etherdev(0, 0); if( (eth16i_debug & version_printed++) == 0) - printk(version); + printk(KERN_INFO "%s", version); dev->base_addr = ioaddr; + +#if 0 + if(dev->irq) { + if(eth16i_set_irq(dev)) { + dev->irq = eth16i_get_irq(ioaddr); + } + + } + else { +#endif - irq = eth16i_get_irq(ioaddr); - dev->irq = irq; + dev->irq = eth16i_get_irq(ioaddr); /* Try to obtain interrupt vector */ - if(request_irq(dev->irq, ð16i_interrupt, 0, "eth16i", dev)) { - printk("%s: %s at %#3x, but is unusable due - conflict on IRQ %d.\n", dev->name, cardname, ioaddr, irq); - return EAGAIN; + + if (request_irq(dev->irq, (void *)ð16i_interrupt, 0, "eth16i", dev)) { + printk(KERN_WARNING "%s: %s at %#3x, but is unusable due conflicting IRQ %d.\n", + dev->name, cardname, ioaddr, dev->irq); + return -EAGAIN; } - printk("%s: %s at %#3x, IRQ %d, ", - dev->name, cardname, ioaddr, dev->irq); +#if 0 + irq2dev_map[dev->irq] = dev; +#endif + + printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ", + dev->name, cardname, ioaddr, dev->irq); /* Let's grab the region */ request_region(ioaddr, ETH16I_IO_EXTENT, "eth16i"); /* Now we will have to lock the chip's io address */ eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); - outb(0x38, ioaddr + TRANSCEIVER_MODE_REG); + outb(0x38, ioaddr + TRANSCEIVER_MODE_REG); - eth16i_initialize(dev); /* Initialize rest of the chip's registers */ + eth16i_initialize(dev); /* Initialize rest of the chip's registers */ /* Now let's same some energy by shutting down the chip ;) */ BITCLR(ioaddr + CONFIG_REG_1, POWERUP); /* Initialize the device structure */ - if(dev->priv == NULL) + if(dev->priv == NULL) { dev->priv = kmalloc(sizeof(struct eth16i_local), GFP_KERNEL); + if(dev->priv == NULL) + return -ENOMEM; + } + memset(dev->priv, 0, sizeof(struct eth16i_local)); dev->open = eth16i_open; @@ -478,7 +595,7 @@ static void eth16i_initialize(struct device *dev) { - short ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; int i, node_w = 0; unsigned char node_byte = 0; @@ -489,11 +606,9 @@ ((unsigned short *)dev->dev_addr)[i] = ntohs(node_val); } - for(i = 0; i < 6; i++) - { + for(i = 0; i < 6; i++) { outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i); - if(boot) - { + if(boot) { printk("%02x", inb(ioaddr + NODE_ID_0 + i)); if(i != 5) printk(":"); @@ -502,14 +617,14 @@ /* Now we will set multicast addresses to accept none */ eth16i_select_regbank(HASH_TABLE_RB, ioaddr); - for(i = 0; i < 8; i++) + for(i = 0; i < 8; i++) outb(0x00, ioaddr + HASH_TABLE_0 + i); /* - Now let's disable the transmitter and receiver, set the buffer ram - cycle time, bus width and buffer data path width. Also we shall - set transmit buffer size and total buffer size. - */ + Now let's disable the transmitter and receiver, set the buffer ram + cycle time, bus width and buffer data path width. Also we shall + set transmit buffer size and total buffer size. + */ eth16i_select_regbank(2, ioaddr); @@ -519,38 +634,56 @@ if( (node_w & 0xFF00) == 0x0800) node_byte |= BUFFER_WIDTH_8; - node_byte |= MBS1; + node_byte |= SRAM_BS1; if( (node_w & 0x00FF) == 64) - node_byte |= MBS0; + node_byte |= SRAM_BS0; node_byte |= DLC_EN | SRAM_CYCLE_TIME_100NS | (ETH16I_TX_BUF_SIZE << 2); outb(node_byte, ioaddr + CONFIG_REG_0); /* We shall halt the transmitting, if 16 collisions are detected */ - outb(RETRANS_AND_HALT_ON_16, ioaddr + COL_16_REG); + outb(HALT_ON_16, ioaddr + COL_16_REG); - if(boot) /* Now set port type */ - { - char *porttype[] = {"BNC", "DIX", "TP", "AUTO"}; +#ifdef MODULE + /* if_port already set by init_module() */ +#else + dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ? + dev->mem_start : E_PORT_FROM_EPROM; +#endif - ushort ptype = eth16i_read_eeprom(ioaddr, E_PORT_SELECT); - dev->if_port = (ptype & 0x00FF); + /* Set interface port type */ + if(boot) { + char *porttype[] = {"BNC", "DIX", "TP", "AUTO", "FROM_EPROM" }; - printk(" %s interface.\n", porttype[dev->if_port]); + switch(dev->if_port) + { + + case E_PORT_FROM_EPROM: + dev->if_port = eth16i_read_eeprom(ioaddr, E_PORT_SELECT); + break; + + case E_PORT_AUTO: + dev->if_port = eth16i_probe_port(ioaddr); + break; + + case E_PORT_BNC: + case E_PORT_TP: + case E_PORT_DIX: + break; + } - if(ptype == E_PORT_AUTO) - ptype = eth16i_probe_port(ioaddr); + printk(" %s interface.\n", porttype[dev->if_port]); - eth16i_set_port(ioaddr, ptype); + eth16i_set_port(ioaddr, dev->if_port); } /* Set Receive Mode to normal operation */ outb(MODE_2, ioaddr + RECEIVE_MODE_REG); } -static int eth16i_probe_port(short ioaddr) +static int eth16i_probe_port(int ioaddr) { int i; int retcode; @@ -579,136 +712,163 @@ eth16i_set_port(ioaddr, i); if(eth16i_debug > 1) - printk("Set port number %d\n", i); + printk(KERN_DEBUG "Set port number %d\n", i); retcode = eth16i_send_probe_packet(ioaddr, dummy_packet, 64); - if(retcode == 0) - { + if(retcode == 0) { retcode = eth16i_receive_probe_packet(ioaddr); - if(retcode != -1) - { + if(retcode != -1) { if(eth16i_debug > 1) - printk("Eth16i interface port found at %d\n", i); + printk(KERN_DEBUG "Eth16i interface port found at %d\n", i); return i; } } else { if(eth16i_debug > 1) - printk("TRANSMIT_DONE timeout\n"); + printk(KERN_DEBUG "TRANSMIT_DONE timeout when probing interface port\n"); } } if( eth16i_debug > 1) - printk("Using default port\n"); + printk(KERN_DEBUG "Using default port\n"); return E_PORT_BNC; } -static void eth16i_set_port(short ioaddr, int porttype) -{ +static void eth16i_set_port(int ioaddr, int porttype) +{ unsigned short temp = 0; eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr); outb(LOOPBACK_CONTROL, ioaddr + TRANSMIT_MODE_REG); temp |= DIS_AUTO_PORT_SEL; - switch(porttype) - { - case E_PORT_BNC : - temp |= AUI_SELECT; - break; + switch(porttype) { - case E_PORT_TP : - break; + case E_PORT_BNC : + temp |= AUI_SELECT; + break; + + case E_PORT_TP : + break; + + case E_PORT_DIX : + temp |= AUI_SELECT; + BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT); + break; + } - case E_PORT_DIX : - temp |= AUI_SELECT; - BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT); - break; - } outb(temp, ioaddr + TRANSCEIVER_MODE_REG); if(eth16i_debug > 1) { - printk("TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG)); - printk("TRANSCEIVER_MODE_REG = %x\n", inb(ioaddr+TRANSCEIVER_MODE_REG)); + printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG)); + printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n", + inb(ioaddr+TRANSCEIVER_MODE_REG)); } } -static int eth16i_send_probe_packet(short ioaddr, unsigned char *b, int l) +static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l) { int starttime; outb(0xff, ioaddr + TX_STATUS_REG); outw(l, ioaddr + DATAPORT); - outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1); + outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1); starttime = jiffies; - outb(TX_START | 1, ioaddr + TRANSMIT_START_REG); + outb(TX_START | 1, ioaddr + TRANSMIT_START_REG); - while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) - if( (jiffies - starttime) > TIMEOUT_TICKS) - break; - return(0); + while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) { + if( (jiffies - starttime) > TX_TIMEOUT) { + return -1; + } + } + + return 0; } -static int eth16i_receive_probe_packet(short ioaddr) +static int eth16i_receive_probe_packet(int ioaddr) { int starttime; starttime = jiffies; - while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) - { - if( (jiffies - starttime) > TIMEOUT_TICKS) - { + while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) { + if( (jiffies - starttime) > TX_TIMEOUT) { + if(eth16i_debug > 1) - printk("Timeout occurred waiting transmit packet received\n"); + printk(KERN_DEBUG "Timeout occured waiting transmit packet received\n"); starttime = jiffies; - while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) - { - if( (jiffies - starttime) > TIMEOUT_TICKS) - { + while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) { + if( (jiffies - starttime) > TX_TIMEOUT) { if(eth16i_debug > 1) - printk("Timeout occurred waiting receive packet\n"); + printk(KERN_DEBUG "Timeout occured waiting receive packet\n"); return -1; } } if(eth16i_debug > 1) - printk("RECEIVE_PACKET\n"); + printk(KERN_DEBUG "RECEIVE_PACKET\n"); return(0); /* Found receive packet */ } } if(eth16i_debug > 1) { - printk("TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG)); - printk("RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG)); + printk(KERN_DEBUG "TRANSMIT_PACKET_RECEIVED %x\n", inb(ioaddr + TX_STATUS_REG)); + printk(KERN_DEBUG "RX_STATUS_REG = %x\n", inb(ioaddr + RX_STATUS_REG)); } return(0); /* Return success */ } -static int eth16i_get_irq(short ioaddr) +#if 0 +static int eth16i_set_irq(struct device* dev) +{ + const int ioaddr = dev->base_addr; + const int irq = dev->irq; + int i = 0; + + if(ioaddr < 0x1000) { + while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq) + i++; + + if(i < NUM_OF_ISA_IRQS) { + u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG); + cbyte = (cbyte & 0x3F) | (i << 6); + outb(cbyte, ioaddr + JUMPERLESS_CONFIG); + return 0; + } + } + else { + printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name); + } + + return -1; + +} +#endif + +static int eth16i_get_irq(int ioaddr) { unsigned char cbyte; if( ioaddr < 0x1000) { cbyte = inb(ioaddr + JUMPERLESS_CONFIG); - return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] ); - } else { /* Oh..the card is EISA so method getting IRQ different */ - unsigned short index = 0; - cbyte = inb(ioaddr + EISA_IRQ_REG); - while( (cbyte & 0x01) == 0) { - cbyte = cbyte >> 1; - index++; - } - return( eth32i_irqmap[ index ] ); + return( eth16i_irqmap[ ((cbyte & 0xC0) >> 6) ] ); + } else { /* Oh..the card is EISA so method getting IRQ different */ + unsigned short index = 0; + cbyte = inb(ioaddr + EISA_IRQ_REG); + while( (cbyte & 0x01) == 0) { + cbyte = cbyte >> 1; + index++; + } + return( eth32i_irqmap[ index ] ); } } -static int eth16i_check_signature(short ioaddr) +static int eth16i_check_signature(int ioaddr) { int i; unsigned char creg[4] = { 0 }; @@ -718,36 +878,37 @@ creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i); if(eth16i_debug > 1) - printk("eth16i: read signature byte %x at %x\n", creg[i], - ioaddr + TRANSMIT_MODE_REG + i); + printk("eth16i: read signature byte %x at %x\n", + creg[i], + ioaddr + TRANSMIT_MODE_REG + i); } creg[0] &= 0x0F; /* Mask collision cnr */ creg[2] &= 0x7F; /* Mask DCLEN bit */ -#if 0 -/* - This was removed because the card was sometimes left to state - from which it couldn't be find anymore. If there is need - to have a more strict check still this have to be fixed. -*/ - if( !( (creg[0] == 0x06) && (creg[1] == 0x41)) ) { +#ifdef 0 + /* + This was removed because the card was sometimes left to state + from which it couldn't be find anymore. If there is need + to more strict check still this have to be fixed. + */ + if( ! ((creg[0] == 0x06) && (creg[1] == 0x41)) ) { if(creg[1] != 0x42) return -1; } #endif - if( !( (creg[2] == 0x36) && (creg[3] == 0xE0)) ) - { - creg[2] &= 0x42; + if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) { + creg[2] &= 0x40; creg[3] &= 0x03; - - if( !( (creg[2] == 0x42) && (creg[3] == 0x00)) ) + + if( !((creg[2] == 0x40) && (creg[3] == 0x00)) ) return -1; } - + if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0) return -1; + if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00) return -1; @@ -763,20 +924,22 @@ data = eth16i_read_eeprom_word(ioaddr); outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG); - return(data); + return(data); } static int eth16i_read_eeprom_word(int ioaddr) { int i; int data = 0; - + for(i = 16; i > 0; i--) { outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG); eeprom_slow_io(); outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG); eeprom_slow_io(); - data = (data << 1) | ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0); + data = (data << 1) | + ((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0); + eeprom_slow_io(); } @@ -800,25 +963,26 @@ eeprom_slow_io(); outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG); eeprom_slow_io(); - } + } } static int eth16i_open(struct device *dev) { struct eth16i_local *lp = (struct eth16i_local *)dev->priv; int ioaddr = dev->base_addr; - + /* Powerup the chip */ outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1); /* Initialize the chip */ - eth16i_initialize(dev); + eth16i_initialize(dev); /* Set the transmit buffer size */ lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03]; - if(eth16i_debug > 3) - printk("%s: transmit buffer size %d\n", dev->name, lp->tx_buf_size); + if(eth16i_debug > 0) + printk(KERN_DEBUG "%s: transmit buffer size %d\n", + dev->name, lp->tx_buf_size); /* Now enable Transmitter and Receiver sections */ BITCLR(ioaddr + CONFIG_REG_0, DLC_EN); @@ -832,15 +996,13 @@ lp->tx_queue_len = 0; /* Turn on interrupts*/ - outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); + outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; -#ifdef MODULE MOD_INC_USE_COUNT; -#endif return 0; } @@ -850,23 +1012,26 @@ struct eth16i_local *lp = (struct eth16i_local *)dev->priv; int ioaddr = dev->base_addr; - lp->open_time = 0; + eth16i_reset(dev); + + /* Turn off interrupts*/ + outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); - dev->tbusy = 1; dev->start = 0; + dev->tbusy = 1; + + lp->open_time = 0; /* Disable transmit and receive */ BITSET(ioaddr + CONFIG_REG_0, DLC_EN); /* Reset the chip */ - outb(0xff, ioaddr + RESET); + /* outb(0xff, ioaddr + RESET); */ + /* outw(0xffff, ioaddr + TX_STATUS_REG); */ + + outb(0x00, ioaddr + CONFIG_REG_1); - /* Save some energy by switching off power */ - BITCLR(ioaddr + CONFIG_REG_1, POWERUP); - -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif return 0; } @@ -875,88 +1040,120 @@ { struct eth16i_local *lp = (struct eth16i_local *)dev->priv; int ioaddr = dev->base_addr; + int status = 0; 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. - */ + + /* + 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 < TIMEOUT_TICKS) /* Let's not rush with our timeout, */ - return 1; /* wait a couple of ticks first */ + if(tickssofar < TX_TIMEOUT) + return 1; - printk("%s: transmit timed out with status %04x, %s ?\n", dev->name, - inw(ioaddr + TX_STATUS_REG), - (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ? - "IRQ conflict" : "network cable problem"); + outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); - /* Let's dump all registers */ - if(eth16i_debug > 0) { - printk("%s: timeout regs: %02x %02x %02x %02x %02x %02x %02x %02x.\n", - dev->name, inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2), - inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5), - inb(ioaddr + 6), inb(ioaddr + 7)); + printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n", + dev->name, + inw(ioaddr + TX_STATUS_REG), + (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ? + "IRQ conflict" : "network cable problem"); + dev->trans_start = jiffies; - printk("lp->tx_queue = %d\n", lp->tx_queue); - printk("lp->tx_queue_len = %d\n", lp->tx_queue_len); - printk("lp->tx_started = %d\n", lp->tx_started); + /* Let's dump all registers */ + if(eth16i_debug > 0) { + printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n", + dev->name, inb(ioaddr + 0), + inb(ioaddr + 1), inb(ioaddr + 2), + inb(ioaddr + 3), inb(ioaddr + 4), + inb(ioaddr + 5), + inb(ioaddr + 6), inb(ioaddr + 7)); + + printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n", + dev->name, inb(ioaddr + TRANSMIT_START_REG), + inb(ioaddr + COL_16_REG)); + + printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue); + printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len); + printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started); } lp->stats.tx_errors++; - /* Now let's try to restart the adaptor */ - - BITSET(ioaddr + CONFIG_REG_0, DLC_EN); - outw(0xffff, ioaddr + RESET); - eth16i_initialize(dev); - outw(0xffff, ioaddr + TX_STATUS_REG); - BITCLR(ioaddr + CONFIG_REG_0, DLC_EN); + eth16i_reset(dev); - lp->tx_started = 0; - lp->tx_queue = 0; - lp->tx_queue_len = 0; + dev->trans_start = jiffies; outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); - dev->tbusy = 0; - dev->trans_start = jiffies; } - /* Block a timer based transmitter from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + /* + If some higher layer thinks we've missed an tx-done interrupt + we are passed NULL. Caution: dev_tint() handles the cli()/sti() + itself + */ + + if(skb == NULL) { +#if LINUX_VERSION_CODE < 0x020100 + dev_tint(dev); +#endif + if(eth16i_debug > 0) + printk(KERN_WARNING "%s: Missed tx-done interrupt.\n", dev->name); + return 0; + } + + /* Block a timer based transmitter from overlapping. + This could better be done with atomic_swap(1, dev->tbusy), + but set_bit() works as well. */ + set_bit(0, (void *)&lp->tx_buf_busy); + /* Turn off TX interrupts */ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); - if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) - printk("%s: Transmitter access conflict.\n", dev->name); + if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) { + printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); + status = -1; + } else { - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; - outw(length, ioaddr + DATAPORT); - - if( ioaddr < 0x1000 ) - outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); - else - { - unsigned char frag = length % 4; - - outsl(ioaddr + DATAPORT, buf, length >> 2); + if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) { + if(eth16i_debug > 0) + printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name); + } + else { + outw(length, ioaddr + DATAPORT); - if( frag != 0 ) - { - outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1); - if( frag == 3 ) - outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC) + 2), 1); + if( ioaddr < 0x1000 ) + outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); + else { + unsigned char frag = length % 4; + + outsl(ioaddr + DATAPORT, buf, length >> 2); + + if( frag != 0 ) { + outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1); + if( frag == 3 ) + outsw(ioaddr + DATAPORT, + (buf + (length & 0xFFFC) + 2), 1); + } } - } - lp->tx_queue++; - lp->tx_queue_len += length + 2; + lp->tx_buffered_packets++; + lp->tx_queue++; + lp->tx_queue_len += length + 2; + + } + + lp->tx_buf_busy = 0; if(lp->tx_started == 0) { /* If the transmitter is idle..always trigger a transmit */ @@ -971,15 +1168,21 @@ /* There is still more room for one more packet in tx buffer */ dev->tbusy = 0; } - + outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); - + /* Turn TX interrupts back on */ /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */ - } + status = 0; + } + +#if LINUX_VERSION_CODE >= 0x020100 dev_kfree_skb(skb); +#else + dev_kfree_skb(skb, FREE_WRITE); +#endif - return 0; + return status; } static void eth16i_rx(struct device *dev) @@ -989,71 +1192,63 @@ int boguscount = MAX_RX_LOOP; /* Loop until all packets have been read */ - while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) - { - /* Read status byte from receive buffer */ + while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) { + + /* Read status byte from receive buffer */ ushort status = inw(ioaddr + DATAPORT); - if(eth16i_debug > 4) - printk("%s: Receiving packet mode %02x status %04x.\n", - dev->name, inb(ioaddr + RECEIVE_MODE_REG), status); + /* Get the size of the packet from receive buffer */ + ushort pkt_len = inw(ioaddr + DATAPORT); - if( !(status & PKT_GOOD) ) - { - /* Hmm..something went wrong. Let's check what error occurred */ + if(eth16i_debug > 4) + printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n", + dev->name, + inb(ioaddr + RECEIVE_MODE_REG), status); + + if( !(status & PKT_GOOD) ) { lp->stats.rx_errors++; - if( status & PKT_SHORT) + + if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) { lp->stats.rx_length_errors++; - if( status & PKT_ALIGN_ERR ) - lp->stats.rx_frame_errors++; - if( status & PKT_CRC_ERR ) - lp->stats.rx_crc_errors++; - if( status & PKT_RX_BUF_OVERFLOW) - lp->stats.rx_over_errors++; + eth16i_reset(dev); + return; + } + else { + eth16i_skip_packet(dev); + lp->stats.rx_dropped++; + } } - else - { /* Ok so now we should have a good packet */ + else { /* Ok so now we should have a good packet */ struct sk_buff *skb; - /* Get the size of the packet from receive buffer */ - ushort pkt_len = inw(ioaddr + DATAPORT); - - if(pkt_len > ETH_FRAME_LEN) - { - printk("%s: %s claimed a very large packet, size of %d bytes.\n", - dev->name, cardname, pkt_len); - outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG); - lp->stats.rx_dropped++; - break; - } skb = dev_alloc_skb(pkt_len + 3); - if( skb == NULL ) - { - printk("%s: Couldn't allocate memory for packet (len %d)\n", - dev->name, pkt_len); - outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG); + if( skb == NULL ) { + printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n", + dev->name, pkt_len); + eth16i_skip_packet(dev); lp->stats.rx_dropped++; break; } + skb->dev = dev; skb_reserve(skb,2); - /* - Now let's get the packet out of buffer. - size is (pkt_len + 1) >> 1, cause we are now reading words - and it has to be even aligned. - */ - - if( ioaddr < 0x1000) - insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), (pkt_len + 1) >> 1); - else - { + + /* + Now let's get the packet out of buffer. + size is (pkt_len + 1) >> 1, cause we are now reading words + and it have to be even aligned. + */ + + if(ioaddr < 0x1000) + insw(ioaddr + DATAPORT, skb_put(skb, pkt_len), + (pkt_len + 1) >> 1); + else { unsigned char *buf = skb_put(skb, pkt_len); unsigned char frag = pkt_len % 4; insl(ioaddr + DATAPORT, buf, pkt_len >> 2); - if(frag != 0) - { + if(frag != 0) { unsigned short rest[2]; rest[0] = inw( ioaddr + DATAPORT ); if(frag == 3) @@ -1067,13 +1262,13 @@ netif_rx(skb); lp->stats.rx_packets++; - if( eth16i_debug > 5 ) - { + if( eth16i_debug > 5 ) { int i; - printk("%s: Received packet of length %d.\n", dev->name, pkt_len); - for(i = 0; i < 14; i++) - printk(" %02x", skb->data[i]); - printk(".\n"); + printk(KERN_DEBUG "%s: Received packet of length %d.\n", + dev->name, pkt_len); + for(i = 0; i < 14; i++) + printk(KERN_DEBUG " %02x", skb->data[i]); + printk(KERN_DEBUG ".\n"); } } /* else */ @@ -1087,16 +1282,16 @@ { int i; - for(i = 0; i < 20; i++) - { - if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == RX_BUFFER_EMPTY) + for(i = 0; i < 20; i++) { + if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == + RX_BUFFER_EMPTY) break; inw(ioaddr + DATAPORT); - outb(RX_BUF_SKIP_PACKET, ioaddr + FILTER_SELF_RX_REG); + outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG); } if(eth16i_debug > 1) - printk("%s: Flushed receive buffer.\n", dev->name); + printk(KERN_DEBUG "%s: Flushed receive buffer.\n", dev->name); } #endif @@ -1108,126 +1303,302 @@ struct device *dev = dev_id; struct eth16i_local *lp; int ioaddr = 0, - status; + status; if(dev == NULL) { - printk("eth16i_interrupt(): irq %d for unknown device. \n", irq); + printk(KERN_WARNING "eth16i_interrupt(): irq %d for unknown device. \n", irq); return; } /* Turn off all interrupts from adapter */ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); + set_bit(0, (void *)&dev->tbusy); /* Set the device busy so that */ + /* eth16i_tx wont be called */ + + if(dev->interrupt) + printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = 1; ioaddr = dev->base_addr; lp = (struct eth16i_local *)dev->priv; - status = inw(ioaddr + TX_STATUS_REG); /* Get the status */ - outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */ + status = inw(ioaddr + TX_STATUS_REG); /* Get the status */ + outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */ if(eth16i_debug > 3) - printk("%s: Interrupt with status %04x.\n", dev->name, status); + printk(KERN_DEBUG "%s: Interrupt with status %04x.\n", dev->name, status); + + if( status & 0x7f00 ) { + + lp->stats.rx_errors++; + + if(status & (BUS_RD_ERR << 8) ) + printk(KERN_WARNING "%s: Bus read error.\n",dev->name); + if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++; + if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++; + if(status & (CRC_ERR << 8) ) lp->stats.rx_crc_errors++; + if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++; + } + if( status & 0x001a) { + + lp->stats.tx_errors++; + + if(status & CR_LOST) lp->stats.tx_carrier_errors++; + if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++; - if( status & 0x00ff ) { /* Let's check the transmit status reg */ - if(status & TX_DONE) - { /* The transmit has been done */ - lp->stats.tx_packets++; - if(lp->tx_queue) - { /* Are there still packets ? */ +#if 0 + if(status & COLLISION) { + lp->stats.collisions += + ((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4); + } +#endif + if(status & COLLISIONS_16) { + if(lp->col_16 < MAX_COL_16) { + lp->col_16++; + lp->stats.collisions++; + /* Resume transmitting, skip failed packet */ + outb(0x02, ioaddr + COL_16_REG); + } + else { + printk(KERN_WARNING "%s: bailing out due to many consecutive 16-in-a-row collisions. Network cable problem?\n", dev->name); + } + } + } + + if( status & 0x00ff ) { /* Let's check the transmit status reg */ + + if(status & TX_DONE) { /* The transmit has been done */ + lp->stats.tx_packets = lp->tx_buffered_packets; + lp->col_16 = 0; + + if(lp->tx_queue) { /* Is there still packets ? */ /* There was packet(s) so start transmitting and write also - how many packets there is to be sent */ + how many packets there is to be sended */ outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG); lp->tx_queue = 0; lp->tx_queue_len = 0; + lp->tx_started = 1; dev->trans_start = jiffies; - dev->tbusy = 0; - mark_bh(NET_BH); + mark_bh(NET_BH); } - else - { + else { lp->tx_started = 0; - dev->tbusy = 0; mark_bh(NET_BH); } } } - if( ( status & 0xff00 ) || - ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) { - eth16i_rx(dev); /* We have packet in receive buffer */ - } - + if( ( status & 0x8000 ) || + ( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) { + eth16i_rx(dev); /* We have packet in receive buffer */ + } + dev->interrupt = 0; - + /* Turn interrupts back on */ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG); - + + if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) { + /* There is still more room for one more packet in tx buffer */ + dev->tbusy = 0; + } + return; } -static void eth16i_multicast(struct device *dev) +static void eth16i_skip_packet(struct device *dev) +{ + int ioaddr = dev->base_addr; + + inw(ioaddr + DATAPORT); + inw(ioaddr + DATAPORT); + inw(ioaddr + DATAPORT); + + outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG); + while( inb( ioaddr + FILTER_SELF_RX_REG ) != 0); +} + +static void eth16i_reset(struct device *dev) { - short ioaddr = dev->base_addr; + struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + int ioaddr = dev->base_addr; + + if(eth16i_debug > 1) + printk(KERN_DEBUG "%s: Resetting device.\n", dev->name); + + BITSET(ioaddr + CONFIG_REG_0, DLC_EN); + outw(0xffff, ioaddr + TX_STATUS_REG); + eth16i_select_regbank(2, ioaddr); + + lp->tx_started = 0; + lp->tx_buf_busy = 0; + lp->tx_queue = 0; + lp->tx_queue_len = 0; + + dev->interrupt = 0; + dev->start = 1; + dev->tbusy = 0; + BITCLR(ioaddr + CONFIG_REG_0, DLC_EN); +} - if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) +static void eth16i_multicast(struct device *dev) +{ + int ioaddr = dev->base_addr; + + if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) { dev->flags|=IFF_PROMISC; /* Must do this */ - outb(3, ioaddr + RECEIVE_MODE_REG); + outb(3, ioaddr + RECEIVE_MODE_REG); } else { outb(2, ioaddr + RECEIVE_MODE_REG); } } -static struct net_device_stats *eth16i_get_stats(struct device *dev) +static struct enet_statistics *eth16i_get_stats(struct device *dev) { struct eth16i_local *lp = (struct eth16i_local *)dev->priv; return &lp->stats; } -static void eth16i_select_regbank(unsigned char banknbr, short ioaddr) +static void eth16i_select_regbank(unsigned char banknbr, int ioaddr) { unsigned char data; data = inb(ioaddr + CONFIG_REG_1); - outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1); + outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1); } #ifdef MODULE -static char devicename[9] = { 0, }; -static struct device dev_eth16i = { - devicename, - 0, 0, 0, 0, - 0, 0, - 0, 0, 0, NULL, eth16i_probe + +static ushort eth16i_parse_mediatype(const char* s) +{ + if(!s) + return E_PORT_FROM_EPROM; + + if (!strncmp(s, "bnc", 3)) + return E_PORT_BNC; + else if (!strncmp(s, "tp", 2)) + return E_PORT_TP; + else if (!strncmp(s, "dix", 3)) + return E_PORT_DIX; + else if (!strncmp(s, "auto", 4)) + return E_PORT_AUTO; + else + return E_PORT_FROM_EPROM; +} + +#define MAX_ETH16I_CARDS 4 /* Max number of Eth16i cards per module */ +#define NAMELEN 8 /* number of chars for storing dev->name */ + +static char namelist[NAMELEN * MAX_ETH16I_CARDS] = { 0, }; +static struct device dev_eth16i[MAX_ETH16I_CARDS] = { + { + NULL, + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL + }, }; -int io = 0x2a0; -int irq = 0; +static int ioaddr[MAX_ETH16I_CARDS] = { 0, }; +#if 0 +static int irq[MAX_ETH16I_CARDS] = { 0, }; +#endif +static char* mediatype[MAX_ETH16I_CARDS] = { 0, }; +static int debug = -1; -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); +#if (LINUX_VERSION_CODE >= 0x20115) +MODULE_AUTHOR("Mika Kuoppala "); +MODULE_DESCRIPTION("ICL EtherTeam 16i/32 driver"); + +MODULE_PARM(ioaddr, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i"); +MODULE_PARM_DESC(ioaddr, "eth16i io base address"); + +#if 0 +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "i"); +MODULE_PARM_DESC(irq, "eth16i interrupt request number"); +#endif + +MODULE_PARM(mediatype, "1-" __MODULE_STRING(MAX_ETH16I_CARDS) "s"); +MODULE_PARM_DESC(mediatype, "eth16i interfaceport mediatype"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "eth16i debug level (0-4)"); +#endif int init_module(void) { - if(io == 0) - printk("eth16i: You should not use auto-probing with insmod!\n"); + int this_dev, found = 0; - dev_eth16i.base_addr = io; - dev_eth16i.irq = irq; - if( register_netdev( &dev_eth16i ) != 0 ) { - printk("eth16i: register_netdev() returned non-zero.\n"); - return -EIO; - } + for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) + { + struct device *dev = &dev_eth16i[this_dev]; + + dev->name = namelist + (NAMELEN*this_dev); + dev->irq = 0; /* irq[this_dev]; */ + dev->base_addr = ioaddr[this_dev]; + dev->init = eth16i_probe; + + if(debug != -1) + eth16i_debug = debug; + + if(eth16i_debug > 1) + printk(KERN_NOTICE "eth16i(%d): interface type %s\n", this_dev, mediatype[this_dev] ? mediatype[this_dev] : "none" ); + dev->if_port = eth16i_parse_mediatype(mediatype[this_dev]); + + if(ioaddr[this_dev] == 0) + { + if(this_dev != 0) break; /* Only autoprobe 1st one */ + + printk(KERN_NOTICE "eth16i.c: Presently autoprobing (not recommended) for a single card.\n"); + } + + if(register_netdev(dev) != 0) + { + printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n", + ioaddr[this_dev]); + + if(found != 0) return 0; + return -ENXIO; + } + + found++; + } return 0; } - + void cleanup_module(void) { - unregister_netdev( &dev_eth16i ); - free_irq( dev_eth16i.irq, &dev_eth16i ); - release_region( dev_eth16i.base_addr, ETH16I_IO_EXTENT ); -} + int this_dev; + for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) + { + struct device* dev = &dev_eth16i[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, ETH16I_IO_EXTENT); + + } + } +} #endif /* MODULE */ + +/* + * Local variables: + * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c" + * alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c" + * tab-width: 8 + * c-basic-offset: 8 + * c-indent-level: 8 + * End: + */ + +/* End of file eth16i.c */ diff -u --recursive --new-file v2.1.125/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c --- v2.1.125/linux/drivers/net/hamradio/baycom_epp.c Tue Jul 21 00:15:31 1998 +++ linux/drivers/net/hamradio/baycom_epp.c Fri Oct 9 12:20:27 1998 @@ -1010,14 +1010,6 @@ /* --------------------------------------------------------------------- */ -static int epp_preempt(void *handle) -{ - /* we cannot relinquish the port in the middle of an operation */ - return 1; -} - -/* --------------------------------------------------------------------- */ - static void epp_wakeup(void *handle) { struct device *dev = (struct device *)handle; @@ -1070,8 +1062,8 @@ } #endif memset(&bc->modem, 0, sizeof(bc->modem)); - if (!(bc->pdev = parport_register_device(pp, dev->name, epp_preempt, epp_wakeup, - epp_interrupt, PARPORT_DEV_LURK, dev))) { + if (!(bc->pdev = parport_register_device(pp, dev->name, NULL, epp_wakeup, + epp_interrupt, PARPORT_DEV_EXCL, dev))) { printk(KERN_ERR "%s: cannot register parport at 0x%lx\n", bc_drvname, pp->base); return -ENXIO; } diff -u --recursive --new-file v2.1.125/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c --- v2.1.125/linux/drivers/net/hamradio/baycom_par.c Tue Jun 9 11:57:29 1998 +++ linux/drivers/net/hamradio/baycom_par.c Fri Oct 9 12:20:27 1998 @@ -357,14 +357,6 @@ /* --------------------------------------------------------------------- */ -static int par96_preempt(void *handle) -{ - /* we cannot relinquish the port in the middle of an operation */ - return 1; -} - -/* --------------------------------------------------------------------- */ - static void par96_wakeup(void *handle) { struct device *dev = (struct device *)handle; @@ -396,8 +388,8 @@ } memset(&bc->modem, 0, sizeof(bc->modem)); bc->hdrv.par.bitrate = 9600; - if (!(bc->pdev = parport_register_device(pp, dev->name, par96_preempt, par96_wakeup, - par96_interrupt, PARPORT_DEV_LURK, dev))) { + if (!(bc->pdev = parport_register_device(pp, dev->name, NULL, par96_wakeup, + par96_interrupt, PARPORT_DEV_EXCL, dev))) { printk(KERN_ERR "baycom_par: cannot register parport at 0x%lx\n", pp->base); return -ENXIO; } diff -u --recursive --new-file v2.1.125/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c --- v2.1.125/linux/drivers/net/hamradio/dmascc.c Thu Sep 17 17:53:36 1998 +++ linux/drivers/net/hamradio/dmascc.c Fri Oct 9 11:56:59 1998 @@ -966,6 +966,7 @@ { struct scc_priv *priv = dev->priv; int cb, cmd = priv->cmd; + unsigned long flags; /* See Figure 2-15. Only overrun and EOF need to be checked. */ @@ -976,9 +977,12 @@ } else if (rc & END_FR) { /* End of frame. Get byte count */ if (dev->dma) { + flags=claim_dma_lock(); disable_dma(dev->dma); clear_dma_ff(dev->dma); cb = BUF_SIZE - get_dma_residue(dev->dma) - 2; + release_dma_lock(flags); + } else { cb = priv->rx_ptr - 2; } @@ -1013,9 +1017,13 @@ } /* Get ready for new frame */ if (dev->dma) { + + flags=claim_dma_lock(); set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]); set_dma_count(dev->dma, BUF_SIZE); enable_dma(dev->dma); + release_dma_lock(flags); + } else { priv->rx_ptr = 0; } @@ -1102,6 +1110,7 @@ struct scc_info *info = priv->info; int i, cmd = priv->cmd; int st, dst, res; + unsigned long flags; /* Read status and reset interrupt bit */ st = read_scc(cmd, R0); @@ -1118,9 +1127,11 @@ /* Get remaining bytes */ i = priv->tx_tail; if (dev->dma) { + flags=claim_dma_lock(); disable_dma(dev->dma); clear_dma_ff(dev->dma); res = get_dma_residue(dev->dma); + release_dma_lock(flags); } else { res = priv->tx_len[i] - priv->tx_ptr; if (res) write_scc(cmd, R0, RES_Tx_P); @@ -1133,9 +1144,11 @@ /* Check if another frame is available and we are allowed to transmit */ if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) { if (dev->dma) { + flags=claim_dma_lock(); set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]); set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]); enable_dma(dev->dma); + release_dma_lock(flags); } else { /* If we have an ESCC, we are allowed to write data bytes immediately. Otherwise we have to wait for the next @@ -1170,12 +1183,14 @@ if (st & DCD) { if (dev->dma) { /* Program DMA controller */ + flags=claim_dma_lock(); disable_dma(dev->dma); clear_dma_ff(dev->dma); set_dma_mode(dev->dma, DMA_MODE_READ); set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]); set_dma_count(dev->dma, BUF_SIZE); enable_dma(dev->dma); + release_dma_lock(flags); /* Configure PackeTwin DMA */ if (info->type == TYPE_TWIN) { outb_p((dev->dma == 1) ? TWIN_DMA_HDX_R1 : TWIN_DMA_HDX_R3, @@ -1195,7 +1210,12 @@ } } else { /* Disable DMA */ - if (dev->dma) disable_dma(dev->dma); + if (dev->dma) + { + flags=claim_dma_lock(); + disable_dma(dev->dma); + release_dma_lock(flags); + } /* Disable receiver */ write_scc(cmd, R3, Rx8); /* DMA disable, RX int disable, Ext int enable */ @@ -1228,11 +1248,13 @@ while (read_scc(cmd, R0) & Rx_CH_AV) read_scc(cmd, R8); priv->rx_over = 0; if (dev->dma) { + flags=claim_dma_lock(); disable_dma(dev->dma); clear_dma_ff(dev->dma); set_dma_addr(dev->dma, (int) priv->rx_buf[priv->rx_head]); set_dma_count(dev->dma, BUF_SIZE); enable_dma(dev->dma); + release_dma_lock(flags); } else { priv->rx_ptr = 0; } @@ -1245,6 +1267,7 @@ struct scc_priv *priv = dev->priv; struct scc_info *info = priv->info; int cmd = priv->cmd; + unsigned long flags; switch (priv->tx_state) { case TX_OFF: @@ -1266,12 +1289,16 @@ priv->tx_state = TX_ACTIVE; if (dev->dma) { /* Program DMA controller */ + + flags=claim_dma_lock(); disable_dma(dev->dma); clear_dma_ff(dev->dma); set_dma_mode(dev->dma, DMA_MODE_WRITE); set_dma_addr(dev->dma, (int) priv->tx_buf[priv->tx_tail]); set_dma_count(dev->dma, priv->tx_len[priv->tx_tail]); enable_dma(dev->dma); + release_dma_lock(flags); + /* Configure PackeTwin DMA */ if (info->type == TYPE_TWIN) { outb_p((dev->dma == 1) ? TWIN_DMA_HDX_T1 : TWIN_DMA_HDX_T3, diff -u --recursive --new-file v2.1.125/linux/drivers/net/hostess_sv11.c linux/drivers/net/hostess_sv11.c --- v2.1.125/linux/drivers/net/hostess_sv11.c Wed Sep 9 14:51:08 1998 +++ linux/drivers/net/hostess_sv11.c Fri Oct 16 23:30:21 1998 @@ -1,3 +1,5 @@ +#define LINUX_21 + /* * Comtrol SV11 card driver * @@ -7,7 +9,7 @@ * Its a genuine Z85230 * * It supports DMA using two DMA channels in SYNC mode. The driver doesn't - * use these facilities (yet). + * use these facilities * * The control port is at io+1, the data at io+3 and turning off the DMA * is done by writing 0 to io+4 @@ -50,7 +52,7 @@ /* * Frame receive. Simple for our card as we do sync ppp and there - * is no funny garbage involved. This is very timing sensitive. + * is no funny garbage involved */ static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) @@ -58,13 +60,12 @@ /* Drop the CRC - its not a good idea to try and negotiate it ;) */ skb_trim(skb, skb->len-2); skb->protocol=htons(ETH_P_WAN_PPP); + skb->mac.raw=skb->data; skb->dev=c->netdevice; /* * Send it to the PPP layer. We dont have time to process * it right now. */ - skb->mac.raw = skb->data; - netif_rx(skb); } @@ -75,15 +76,24 @@ static int hostess_open(struct device *d) { struct sv11_device *sv11=d->priv; - int err; + int err = -1; /* * Link layer up */ - if(dma) - err=z8530_sync_dma_open(d, &sv11->sync.chanA); - else - err=z8530_sync_open(d, &sv11->sync.chanA); + switch(dma) + { + case 0: + err=z8530_sync_open(d, &sv11->sync.chanA); + break; + case 1: + err=z8530_sync_dma_open(d, &sv11->sync.chanA); + break; + case 2: + err=z8530_sync_txdma_open(d, &sv11->sync.chanA); + break; + } + if(err) return err; /* @@ -92,10 +102,18 @@ err=sppp_open(d); if(err) { - if(dma) - z8530_sync_dma_close(d, &sv11->sync.chanA); - else - z8530_sync_close(d, &sv11->sync.chanA); + switch(dma) + { + case 0: + z8530_sync_close(d, &sv11->sync.chanA); + break; + case 1: + z8530_sync_dma_close(d, &sv11->sync.chanA); + break; + case 2: + z8530_sync_txdma_close(d, &sv11->sync.chanA); + break; + } return err; } sv11->sync.chanA.rx_function=hostess_input; @@ -123,10 +141,19 @@ * Link layer down */ d->tbusy=1; - if(dma) - z8530_sync_dma_close(d, &sv11->sync.chanA); - else - z8530_sync_close(d, &sv11->sync.chanA); + + switch(dma) + { + case 0: + z8530_sync_close(d, &sv11->sync.chanA); + break; + case 1: + z8530_sync_dma_close(d, &sv11->sync.chanA); + break; + case 2: + z8530_sync_txdma_close(d, &sv11->sync.chanA); + break; + } MOD_DEC_USE_COUNT; return 0; } @@ -135,10 +162,10 @@ { struct sv11_device *sv11=d->priv; /* z8530_ioctl(d,&sv11->sync.chanA,ifr,cmd) */ - return sppp_do_ioctl(d, ifr, cmd); + return sppp_do_ioctl(d, ifr,cmd); } -static struct net_device_stats *hostess_get_stats(struct device *d) +static struct enet_statistics *hostess_get_stats(struct device *d) { struct sv11_device *sv11=d->priv; if(sv11) @@ -157,6 +184,7 @@ return z8530_queue_xmit(&sv11->sync.chanA, skb); } +#ifdef LINUX_21 static int hostess_neigh_setup(struct neighbour *n) { if (n->nud_state == NUD_NONE) { @@ -176,6 +204,15 @@ return 0; } +#else + +static int return_0(struct device *d) +{ + return 0; +} + +#endif + /* * Description block for a Comtrol Hostess SV11 card */ @@ -243,13 +280,17 @@ * You can have DMA off or 1 and 3 thats the lot * on the Comtrol. */ - dev->chanA.txdma=1; - dev->chanA.rxdma=3; - outb(14, iobase+4); /* DMA on */ + dev->chanA.txdma=3; + dev->chanA.rxdma=1; + outb(0x03|0x08, iobase+4); /* DMA on */ if(request_dma(dev->chanA.txdma, "Hostess SV/11 (TX)")!=0) goto fail; - if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0) - goto dmafail; + + if(dma==1) + { + if(request_dma(dev->chanA.rxdma, "Hostess SV/11 (RX)")!=0) + goto dmafail; + } } save_flags(flags); cli(); @@ -259,7 +300,10 @@ */ if(z8530_init(dev)!=0) + { + printk(KERN_ERR "Z8530 series device not found.\n"); goto dmafail2; + } z8530_channel_load(&dev->chanB, z8530_dead_port); if(dev->type==Z85C30) z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); @@ -269,8 +313,6 @@ restore_flags(flags); - printk(KERN_INFO "begin loading hdlc\n"); - /* * Now we can take the IRQ */ @@ -291,7 +333,6 @@ * Local fields */ sprintf(sv->name,"hdlc%d", i); - printk("Filling in device '%s' at %p\n", sv->name, d); d->name = sv->name; d->base_addr = iobase; @@ -305,8 +346,12 @@ d->get_stats = hostess_get_stats; d->set_multicast_list = NULL; d->do_ioctl = hostess_ioctl; +#ifdef LINUX_21 d->neigh_setup = hostess_neigh_setup_dev; dev_init_buffers(d); +#else + d->init = return_0; +#endif d->set_mac_address = NULL; if(register_netdev(d)==-1) @@ -322,11 +367,11 @@ } } dmafail2: - if(!dma) - goto fail; - free_dma(dev->chanA.rxdma); + if(dma==1) + free_dma(dev->chanA.rxdma); dmafail: - free_dma(dev->chanA.txdma); + if(dma) + free_dma(dev->chanA.txdma); fail: free_irq(irq, dev); fail2: @@ -342,8 +387,11 @@ z8530_shutdown(&dev->sync); unregister_netdev(&dev->netdev.dev); free_irq(dev->sync.irq, dev); - free_dma(dev->sync.chanA.rxdma); - free_dma(dev->sync.chanA.txdma); + if(dma) + { + free_dma(dev->sync.chanA.rxdma); + free_dma(dev->sync.chanA.txdma); + } release_region(dev->sync.chanA.ctrlio-1, 8); } @@ -352,6 +400,7 @@ static int io=0x200; static int irq=9; +#ifdef LINUX_21 MODULE_PARM(io,"i"); MODULE_PARM_DESC(io, "The I/O base of the Comtrol Hostess SV11 card"); MODULE_PARM(dma,"i"); @@ -361,12 +410,13 @@ MODULE_AUTHOR("Bulding Number Three Ltd"); MODULE_DESCRIPTION("Modular driver for the Comtrol Hostess SV11"); +#endif static struct sv11_device *sv11_unit; int init_module(void) { - printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.02.\n"); + printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.01.\n"); printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); if(dma) printk(KERN_WARNING "DMA mode probably wont work right now.\n"); diff -u --recursive --new-file v2.1.125/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.1.125/linux/drivers/net/lance.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/net/lance.c Fri Oct 9 11:56:59 1998 @@ -377,6 +377,7 @@ unsigned char hpJ2405A = 0; /* HP ISA adaptor */ int hp_builtin = 0; /* HP on-board ethernet. */ static int did_version = 0; /* Already printed version info. */ + unsigned long flags; /* First we look for special cases. Check for HP's on-board ethernet by looking for 'HP' in the BIOS. @@ -563,8 +564,11 @@ outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */ if (request_dma(dma, chipname)) continue; + + flags=claim_dma_lock(); set_dma_mode(dma, DMA_MODE_CASCADE); enable_dma(dma); + release_dma_lock(flags); /* Trigger an initialization. */ outw(0x0001, ioaddr+LANCE_DATA); @@ -576,7 +580,9 @@ printk(", DMA %d.\n", dev->dma); break; } else { + flags=claim_dma_lock(); disable_dma(dma); + release_dma_lock(flags); free_dma(dma); } } @@ -649,8 +655,10 @@ /* The DMA controller is used as a no-operation slave, "cascade mode". */ if (dev->dma != 4) { + unsigned long flags=claim_dma_lock(); enable_dma(dev->dma); set_dma_mode(dev->dma, DMA_MODE_CASCADE); + release_dma_lock(flags); } /* Un-Reset the LANCE, needed only for the NE2100. */ @@ -1121,7 +1129,11 @@ outw(0x0004, ioaddr+LANCE_DATA); if (dev->dma != 4) + { + unsigned long flags=claim_dma_lock(); disable_dma(dev->dma); + release_dma_lock(flags); + } free_irq(dev->irq, dev); diff -u --recursive --new-file v2.1.125/linux/drivers/net/ltpc.c linux/drivers/net/ltpc.c --- v2.1.125/linux/drivers/net/ltpc.c Mon Feb 23 18:12:05 1998 +++ linux/drivers/net/ltpc.c Fri Oct 9 11:56:59 1998 @@ -352,13 +352,17 @@ /* called *only* from idle, non-reentrant */ int dma = dev->dma; int base = dev->base_addr; + unsigned long flags; + + flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma,DMA_MODE_READ); set_dma_addr(dma,virt_to_bus(ltdmacbuf)); set_dma_count(dma,50); enable_dma(dma); + release_dma_lock(flags); inb_p(base+3); inb_p(base+2); @@ -370,13 +374,16 @@ { int dma = dev->dma; int base = dev->base_addr; + unsigned long flags; + flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma,DMA_MODE_READ); set_dma_addr(dma,virt_to_bus(ltdmabuf)); set_dma_count(dma,800); enable_dma(dma); + release_dma_lock(flags); inb_p(base+3); inb_p(base+2); @@ -391,21 +398,25 @@ /* on entry, 0xfb and ltdmabuf holds data */ int dma = dev->dma; int base = dev->base_addr; - - + unsigned long flags; + + flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma,DMA_MODE_WRITE); set_dma_addr(dma,virt_to_bus(ltdmabuf)); set_dma_count(dma,800); enable_dma(dma); - + release_dma_lock(flags); + inb_p(base+3); inb_p(base+2); if ( wait_timeout(dev,0xfb) ) { + flags=claim_dma_lock(); printk("timed out in handlewrite, dma res %d\n", get_dma_residue(dev->dma) ); + release_dma_lock(flags); } } @@ -415,15 +426,17 @@ /* on exit, ltdmabuf holds data */ int dma = dev->dma; int base = dev->base_addr; + unsigned long flags; - - + + flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma,DMA_MODE_READ); set_dma_addr(dma,virt_to_bus(ltdmabuf)); set_dma_count(dma,800); enable_dma(dma); + release_dma_lock(flags); inb_p(base+3); inb_p(base+2); @@ -435,14 +448,16 @@ /* on entry, 0xfa and ltdmacbuf holds command */ int dma = dev->dma; int base = dev->base_addr; + unsigned long flags; + flags=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma,DMA_MODE_WRITE); set_dma_addr(dma,virt_to_bus(ltdmacbuf)); set_dma_count(dma,50); enable_dma(dma); - + release_dma_lock(flags); inb_p(base+3); inb_p(base+2); if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n"); @@ -978,6 +993,7 @@ int probe3, probe4, probe9; unsigned short straymask; unsigned long flags; + unsigned long f; err = ltpc_init(dev); if (err) return err; @@ -1089,6 +1105,7 @@ inb_p(base+6); /* tri-state interrupt line */ timeout = jiffies+100; + while(timeout>jiffies) { /* wait for the card to complete initialization */ } @@ -1098,21 +1115,26 @@ /* set up both dma 1 and 3 for read call */ if (!request_dma(1,"ltpc")) { + + f=claim_dma_lock(); disable_dma(1); clear_dma_ff(1); set_dma_mode(1,DMA_MODE_WRITE); set_dma_addr(1,virt_to_bus(ltdmabuf)); set_dma_count(1,sizeof(struct lt_mem)); enable_dma(1); + release_dma_lock(f); dma|=1; } if (!request_dma(3,"ltpc")) { + f=claim_dma_lock(); disable_dma(3); clear_dma_ff(3); set_dma_mode(3,DMA_MODE_WRITE); set_dma_addr(3,virt_to_bus(ltdmabuf)); set_dma_count(3,sizeof(struct lt_mem)); enable_dma(3); + release_dma_lock(f); dma|=2; } @@ -1174,13 +1196,15 @@ if(debug&DEBUG_VERBOSE) { printk("finishing up transfer\n"); } - + + f=claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); set_dma_mode(dma,DMA_MODE_READ); set_dma_addr(dma,virt_to_bus(ltdmabuf)); set_dma_count(dma,0x100); enable_dma(dma); + release_dma_lock(f); (void) inb_p(base+3); (void) inb_p(base+2); diff -u --recursive --new-file v2.1.125/linux/drivers/net/ni65.c linux/drivers/net/ni65.c --- v2.1.125/linux/drivers/net/ni65.c Sun Jun 7 11:16:32 1998 +++ linux/drivers/net/ni65.c Fri Oct 9 11:56:59 1998 @@ -351,6 +351,7 @@ { int i,j; struct priv *p; + unsigned long flags; for(i=0;idev_addr,0,0); /* trigger memory access */ + + flags=claim_dma_lock(); disable_dma(dma); free_dma(dma); + release_dma_lock(flags); + if(readreg(CSR0) & CSR0_IDON) break; } @@ -718,20 +727,25 @@ { int i; struct priv *p = (struct priv *) dev->priv; + unsigned long flags; p->lock = 0; p->xmit_queued = 0; + flags=claim_dma_lock(); disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */ set_dma_mode(dev->dma,DMA_MODE_CASCADE); enable_dma(dev->dma); + release_dma_lock(flags); outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */ if( (i=readreg(CSR0) ) != 0x4) { printk(KERN_ERR "%s: can't RESET %s card: %04x\n",dev->name, cards[p->cardno].cardname,(int) i); + flags=claim_dma_lock(); disable_dma(dev->dma); + release_dma_lock(flags); return 0; } @@ -782,7 +796,9 @@ return 1; /* ->OK */ } printk(KERN_ERR "%s: can't init lance, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG)); + flags=claim_dma_lock(); disable_dma(dev->dma); + release_dma_lock(flags); return 0; /* ->Error */ } @@ -1167,8 +1183,10 @@ } #ifdef MODULE +static char devicename[9] = { 0, }; + static struct device dev_ni65 = { - " ", /* "ni6510": device name inserted by net_init.c */ + devicename, /* "ni6510": device name inserted by net_init.c */ 0, 0, 0, 0, 0x360, 9, /* I/O address, IRQ */ 0, 0, 0, NULL, ni65_probe }; diff -u --recursive --new-file v2.1.125/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.1.125/linux/drivers/net/plip.c Thu Sep 17 17:53:36 1998 +++ linux/drivers/net/plip.c Fri Oct 9 12:20:27 1998 @@ -242,7 +242,10 @@ pardev = parport_register_device(pb, dev->name, plip_preempt, plip_wakeup, plip_interrupt, - PARPORT_DEV_LURK, dev); + 0, dev); + + if (!pardev) + return -ENODEV; printk(KERN_INFO "%s", version); printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d\n", dev->name, diff -u --recursive --new-file v2.1.125/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.1.125/linux/drivers/net/sdla_fr.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/net/sdla_fr.c Fri Oct 9 11:56:59 1998 @@ -650,8 +650,8 @@ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; + dev->mem_start = (unsigned long)wandev->maddr; + dev->mem_end = dev->mem_start + wandev->msize - 1; /* Set transmit buffer queue length */ dev->tx_queue_len = 10; /* Initialize socket buffers */ diff -u --recursive --new-file v2.1.125/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.1.125/linux/drivers/net/sdla_ppp.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/net/sdla_ppp.c Fri Oct 9 11:56:59 1998 @@ -412,8 +412,8 @@ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; + dev->mem_start = (unsigned long)wandev->maddr; + dev->mem_end = dev->mem_start + wandev->msize - 1; /* Set transmit buffer queue length */ dev->tx_queue_len = 100; /* Initialize socket buffers */ diff -u --recursive --new-file v2.1.125/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c --- v2.1.125/linux/drivers/net/sdla_x25.c Fri Oct 9 13:27:09 1998 +++ linux/drivers/net/sdla_x25.c Fri Oct 9 11:56:59 1998 @@ -560,8 +560,8 @@ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; - dev->mem_start = wandev->maddr; - dev->mem_end = wandev->maddr + wandev->msize - 1; + dev->mem_start = (unsigned long)wandev->maddr; + dev->mem_end = dev->mem_end + wandev->msize - 1; /* Set transmit buffer queue length */ dev->tx_queue_len = 10; diff -u --recursive --new-file v2.1.125/linux/drivers/net/sdladrv.c linux/drivers/net/sdladrv.c --- v2.1.125/linux/drivers/net/sdladrv.c Wed Sep 9 14:51:08 1998 +++ linux/drivers/net/sdladrv.c Fri Oct 9 11:56:59 1998 @@ -421,10 +421,10 @@ return err; } } - else if (!get_option_index(dpmbase_opt, virt_to_phys((void *)hw->dpmbase))) + else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase))) { printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n", - modname, hw->dpmbase) + modname, virt_to_phys(hw->dpmbase)) ; return -EINVAL; } @@ -432,16 +432,14 @@ { printk(KERN_ERR "%s: 8K memory region at 0x%lX is not available!\n", - modname, hw->dpmbase) - ; + modname, virt_to_phys(hw->dpmbase)); return -EINVAL; } printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n", - modname, virt_to_phys((void *)hw->dpmbase)) - ; + modname, virt_to_phys(hw->dpmbase)); + printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n", - modname, hw->memory / 1024) - ; + modname, hw->memory / 1024); /* Load firmware. If loader fails then shut down adapter */ err = sdla_load(hw, sfm, len); @@ -830,7 +828,7 @@ /* Relocate window and copy block of data */ err = sdla_mapmem(hw, curvec); - memcpy((void*)buf, (void*)(hw->dpmbase + curpos), curlen); + memcpy(buf, (void *)((u8 *)hw->dpmbase + curpos), curlen); addr += curlen; (char*)buf += curlen; len -= curlen; @@ -872,7 +870,7 @@ /* Relocate window and copy block of data */ sdla_mapmem(hw, curvec); - memcpy((void*)(hw->dpmbase + curpos), (void*)buf, curlen); + memcpy((void*)((u8 *)hw->dpmbase + curpos), buf, curlen); addr += curlen; (char*)buf += curlen; len -= curlen; @@ -980,7 +978,7 @@ for (i = opt[0]; i && err; --i) { - hw->dpmbase = (unsigned long )(phys_to_virt(opt[i])); + hw->dpmbase = phys_to_virt(opt[i]); err = sdla_setdpm(hw); } return err; @@ -1001,7 +999,7 @@ /* Shut down card and verify memory region */ sdla_down(hw); - if (check_memregion((void*)hw->dpmbase, hw->dpmsize)) + if (check_memregion(hw->dpmbase, hw->dpmsize)) return -EINVAL ; @@ -1154,7 +1152,7 @@ for (memsize = 0, winsize = hw->dpmsize; !sdla_mapmem(hw, memsize) && - (test_memregion((void*)hw->dpmbase, winsize) == winsize) + (test_memregion(hw->dpmbase, winsize) == winsize) ; memsize += winsize) ; @@ -1176,7 +1174,7 @@ if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) return -EIO ; - data = (void*)(hw->dpmbase + (sfminfo->dataoffs - hw->vector)); + data = (void*)((u8 *)hw->dpmbase + (sfminfo->dataoffs - hw->vector)); memset(data, 0, sfminfo->datasize); data[0x00] = make_config_byte(hw); @@ -1229,7 +1227,7 @@ static int sdla_start (sdlahw_t* hw, unsigned addr) { unsigned port = hw->port; - unsigned char* bootp; + unsigned char *bootp; int err, tmp, i; if (!port) return -EFAULT; @@ -1237,14 +1235,15 @@ switch (hw->type) { case SDLA_S502A: - bootp = (void*)(hw->dpmbase + 0x66); + bootp = hw->dpmbase; + bootp += 0x66; break; case SDLA_S502E: case SDLA_S503: case SDLA_S507: case SDLA_S508: - bootp = (void*)hw->dpmbase; + bootp = hw->dpmbase; break; default: @@ -1333,7 +1332,7 @@ hw->regs[1] = 0xFF; /* Verify configuration options */ - i = get_option_index(s502a_dpmbase_options, virt_to_phys((void *)hw->dpmbase)); + i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) return -EINVAL ; @@ -1372,7 +1371,7 @@ ; /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys((void *)hw->dpmbase)); + i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) return -EINVAL ; @@ -1416,7 +1415,7 @@ ; /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys((void *)hw->dpmbase)); + i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) return -EINVAL ; @@ -1458,7 +1457,7 @@ ; /* Verify configuration options */ - i = get_option_index(s507_dpmbase_options, virt_to_phys((void *)hw->dpmbase)); + i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) return -EINVAL ; @@ -1515,7 +1514,7 @@ ; /* Verify configuration options */ - i = get_option_index(s508_dpmbase_options, virt_to_phys((void *)hw->dpmbase)); + i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) return -EINVAL ; diff -u --recursive --new-file v2.1.125/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c --- v2.1.125/linux/drivers/net/sdlamain.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/net/sdlamain.c Fri Oct 9 11:56:59 1998 @@ -269,9 +269,9 @@ card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; /* Compute the virtual address of the card in kernel space */ if(conf->maddr) - card->hw.dpmbase = (unsigned long)phys_to_virt(conf->maddr); + card->hw.dpmbase = phys_to_virt(conf->maddr); else /* But 0 means NULL */ - card->hw.dpmbase = conf->maddr; + card->hw.dpmbase = (void *)conf->maddr; card->hw.dpmsize = SDLA_WINDOWSIZE; card->hw.type = conf->hw_opt[0]; @@ -470,8 +470,8 @@ } /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ sti(); /* Not ideal but tough we have to do this */ - if(copy_to_user((void*)(dump.ptr), - (void*)(card->hw.dpmbase + pos), len)) + if(copy_to_user((void *)dump.ptr, + (u8 *)card->hw.dpmbase + pos, len)) return -EFAULT; cli(); dump.length -= len; diff -u --recursive --new-file v2.1.125/linux/drivers/net/sktr.c linux/drivers/net/sktr.c --- v2.1.125/linux/drivers/net/sktr.c Wed Jul 1 19:38:54 1998 +++ linux/drivers/net/sktr.c Fri Oct 9 11:56:59 1998 @@ -298,6 +298,7 @@ __initfunc(static int sktr_isa_chk_card(struct device *dev, int ioaddr)) { int i, err; + unsigned long flags; err = sktr_isa_chk_ioaddr(ioaddr); if(err < 0) @@ -373,9 +374,11 @@ } } + flags=claim_dma_lock(); disable_dma(dev->dma); set_dma_mode(dev->dma, DMA_MODE_CASCADE); enable_dma(dev->dma); + release_dma_lock(flags); printk("%s: %s found at %#4x, using IRQ %d and DMA %d.\n", dev->name, AdapterName, ioaddr, dev->irq, dev->dma); @@ -1446,7 +1449,12 @@ sktr_disable_interrupts(dev); if(dev->dma > 0) + { + unsigned long flags=claim_dma_lock(); disable_dma(dev->dma); + release_dma_lock(flags); + } + outw(0xFF00, dev->base_addr + SIFCMD); if(dev->dma > 0) outb(0xff, dev->base_addr + POSREG); diff -u --recursive --new-file v2.1.125/linux/drivers/net/syncppp.c linux/drivers/net/syncppp.c --- v2.1.125/linux/drivers/net/syncppp.c Wed Sep 9 14:51:08 1998 +++ linux/drivers/net/syncppp.c Fri Oct 9 11:56:59 1998 @@ -770,6 +770,7 @@ sp->obytes += skb->len; /* Control is high priority so it doesnt get queued behind data */ skb->priority=1; + skb->dev = dev; dev_queue_xmit(skb); } @@ -811,6 +812,7 @@ ch->par2, ch->rel, ch->time0, ch->time1); sp->obytes += skb->len; skb->priority=1; + skb->dev = dev; dev_queue_xmit(skb); } @@ -861,9 +863,11 @@ { case SPPPIOCCISCO: sp->pp_flags|=PP_CISCO; + dev->type = ARPHRD_HDLC; break; case SPPPIOCPPP: sp->pp_flags&=~PP_CISCO; + dev->type = ARPHRD_PPP; break; default: return -EINVAL; @@ -908,7 +912,7 @@ dev->hard_header = sppp_hard_header; dev->rebuild_header = sppp_rebuild_header; dev->tx_queue_len = 10; - dev->type = ARPHRD_PPP; + dev->type = ARPHRD_HDLC; dev->addr_len = 0; dev->hard_header_len = sizeof(struct ppp_header); dev->mtu = PPP_MTU; @@ -924,7 +928,7 @@ dev->change_mtu = sppp_change_mtu; dev->hard_header_cache = NULL; dev->header_cache_update = NULL; - dev->flags = IFF_MULTICAST; + dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; dev_init_buffers(dev); } diff -u --recursive --new-file v2.1.125/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.1.125/linux/drivers/net/via-rhine.c Fri Oct 9 13:27:09 1998 +++ linux/drivers/net/via-rhine.c Fri Oct 9 11:40:54 1998 @@ -65,7 +65,6 @@ #define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ /* Include files, designed to support most kernel versions 2.0.0 and later. */ -#include #include #ifdef MODULE #ifdef MODVERSIONS diff -u --recursive --new-file v2.1.125/linux/drivers/net/z85230.c linux/drivers/net/z85230.c --- v2.1.125/linux/drivers/net/z85230.c Wed Sep 9 14:51:08 1998 +++ linux/drivers/net/z85230.c Fri Oct 9 11:56:59 1998 @@ -152,8 +152,9 @@ 3, ENT_HM|RxCRC_ENAB|Rx8, 5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR, 9, 0, /* Disable interrupts */ + 6, 0xFF, 7, FLAG, - 10, ABUNDER|MARKIDLE|NRZ|CRCPS, + 10, ABUNDER|NRZ|CRCPS,/*MARKIDLE ??*/ 11, TCTRxCP, 14, DISDPLL, 15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE, @@ -176,8 +177,9 @@ 3, ENT_HM|RxCRC_ENAB|Rx8, 5, TxCRC_ENAB|RTS|TxENAB|Tx8|DTR, 9, 0, /* Disable interrupts */ + 6, 0xFF, 7, FLAG, - 10, ABUNDER|MARKIDLE|NRZ|CRCPS, + 10, ABUNDER|NRZ|CRCPS, /* MARKIDLE?? */ 11, TCTRxCP, 14, DISDPLL, 15, DCDIE|SYNCIE|CTSIE|TxUIE|BRKIE, @@ -389,6 +391,8 @@ if(chan->rxdma_on) { /* Special condition check only */ + u8 r7=read_zsreg(chan, R7); + u8 r6=read_zsreg(chan, R6); u8 status=read_zsreg(chan, R1); if(status&END_FR) { @@ -418,6 +422,7 @@ static void z8530_dma_status(struct z8530_channel *chan) { + unsigned long flags; u8 status=read_zsreg(chan, R0); u8 altered=chan->status^status; @@ -427,10 +432,12 @@ { if(status&TxEOM) { + flags=claim_dma_lock(); /* Transmit underrun */ disable_dma(chan->txdma); clear_dma_ff(chan->txdma); chan->txdma_on=0; + release_dma_lock(flags); z8530_tx_done(chan); } } @@ -461,6 +468,15 @@ EXPORT_SYMBOL(z8530_dma_sync); +struct z8530_irqhandler z8530_txdma_sync= +{ + z8530_rx, + z8530_dma_tx, + z8530_dma_status +}; + +EXPORT_SYMBOL(z8530_txdma_sync); + /* * Interrupt vectors for a Z8530 that is in 'parked' mode. * For machines with PCI Z85x30 cards, or level triggered interrupts @@ -566,7 +582,7 @@ irqs->status(&dev->chanB); } } - if(work==200) + if(work==5000) printk(KERN_ERR "%s: interrupt jammed - abort(0x%X)!\n", dev->name, intr); /* Ok all done */ locker=0; @@ -619,6 +635,8 @@ int z8530_sync_dma_open(struct device *dev, struct z8530_channel *c) { + unsigned long flags; + c->sync = 1; c->mtu = dev->mtu; c->count = 0; @@ -665,6 +683,7 @@ return -ENOBUFS; } c->tx_dma_used=0; + c->dma_tx = 1; c->dma_num=0; c->dma_ready=1; @@ -672,13 +691,23 @@ * Enable DMA control mode */ - c->regs[R1]|= WT_RDY_RT|WT_FN_RDYFN; + /* + * TX DMA via DIR/REQ + */ + + c->regs[R14]|= DTRREQ; + write_zsreg(c, R14, c->regs[R14]); + + /* + * RX DMA via W/Req + */ + + c->regs[R1]|= WT_FN_RDYFN; + c->regs[R1]|= WT_RDY_RT; c->regs[R1]|= INT_ERR_Rx; write_zsreg(c, R1, c->regs[R1]); c->regs[R1]|= WT_RDY_ENAB; write_zsreg(c, R1, c->regs[R1]); - c->regs[R14]|= DTRREQ; - write_zsreg(c, R14, c->regs[R14]); /* * DMA interrupts @@ -688,9 +717,11 @@ * Set up the DMA configuration */ + flags=claim_dma_lock(); + disable_dma(c->rxdma); clear_dma_ff(c->rxdma); - set_dma_mode(c->rxdma, DMA_MODE_READ); + set_dma_mode(c->rxdma, DMA_MODE_READ|0x10); set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[0])); set_dma_count(c->rxdma, c->mtu); enable_dma(c->rxdma); @@ -700,6 +731,8 @@ set_dma_mode(c->txdma, DMA_MODE_WRITE); disable_dma(c->txdma); + release_dma_lock(flags); + /* * Select the DMA interrupt handlers */ @@ -719,6 +752,8 @@ int z8530_sync_dma_close(struct device *dev, struct z8530_channel *c) { u8 chk; + unsigned long flags; + c->irqs = &z8530_nop; c->max = 0; c->sync = 0; @@ -726,12 +761,17 @@ /* * Disable the PC DMA channels */ - + + flags=claim_dma_lock(); disable_dma(c->rxdma); clear_dma_ff(c->rxdma); + c->rxdma_on = 0; + disable_dma(c->txdma); clear_dma_ff(c->txdma); + release_dma_lock(flags); + c->txdma_on = 0; c->tx_dma_used = 0; @@ -775,6 +815,137 @@ EXPORT_SYMBOL(z8530_sync_dma_close); +int z8530_sync_txdma_open(struct device *dev, struct z8530_channel *c) +{ + printk("Opening sync interface for TX-DMA\n"); + c->sync = 1; + c->mtu = dev->mtu; + c->count = 0; + c->skb = NULL; + c->skb2 = NULL; + + /* + * Load the PIO receive ring + */ + + z8530_rx_done(c); + z8530_rx_done(c); + + /* + * Load the DMA interfaces up + */ + + c->rxdma_on = 0; + c->txdma_on = 0; + + c->tx_dma_buf[0]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); + if(c->tx_dma_buf[0]==NULL) + { + kfree(c->rx_buf[0]); + kfree(c->rx_buf[1]); + c->rx_buf[0]=NULL; + return -ENOBUFS; + } + c->tx_dma_buf[1]=kmalloc(c->mtu, GFP_KERNEL|GFP_DMA); + if(c->tx_dma_buf[1]==NULL) + { + kfree(c->tx_dma_buf[0]); + kfree(c->rx_buf[0]); + kfree(c->rx_buf[1]); + c->rx_buf[0]=NULL; + c->rx_buf[1]=NULL; + c->tx_dma_buf[0]=NULL; + return -ENOBUFS; + } + c->tx_dma_used=0; + c->dma_num=0; + c->dma_ready=1; + c->dma_tx = 1; + + /* + * Enable DMA control mode + */ + + /* + * TX DMA via DIR/REQ + */ + c->regs[R14]|= DTRREQ; + write_zsreg(c, R14, c->regs[R14]); + + /* + * Set up the DMA configuration + */ + + disable_dma(c->txdma); + clear_dma_ff(c->txdma); + set_dma_mode(c->txdma, DMA_MODE_WRITE); + disable_dma(c->txdma); + + /* + * Select the DMA interrupt handlers + */ + + c->rxdma_on = 0; + c->txdma_on = 1; + c->tx_dma_used = 1; + + c->irqs = &z8530_txdma_sync; + printk("Loading RX\n"); + z8530_rtsdtr(c,1); + printk("Rx interrupts ON\n"); + write_zsreg(c, R3, c->regs[R3]|RxENABLE); + return 0; +} + +EXPORT_SYMBOL(z8530_sync_txdma_open); + +int z8530_sync_txdma_close(struct device *dev, struct z8530_channel *c) +{ + u8 chk; + c->irqs = &z8530_nop; + c->max = 0; + c->sync = 0; + + /* + * Disable the PC DMA channels + */ + + disable_dma(c->txdma); + clear_dma_ff(c->txdma); + c->txdma_on = 0; + c->tx_dma_used = 0; + + /* + * Disable DMA control mode + */ + + c->regs[R1]&= ~WT_RDY_ENAB; + write_zsreg(c, R1, c->regs[R1]); + c->regs[R1]&= ~(WT_RDY_RT|WT_FN_RDYFN|INT_ERR_Rx); + c->regs[R1]|= INT_ALL_Rx; + write_zsreg(c, R1, c->regs[R1]); + c->regs[R14]&= ~DTRREQ; + write_zsreg(c, R14, c->regs[R14]); + + if(c->tx_dma_buf[0]) + { + kfree(c->tx_dma_buf[0]); + c->tx_dma_buf[0]=NULL; + } + if(c->tx_dma_buf[1]) + { + kfree(c->tx_dma_buf[1]); + c->tx_dma_buf[1]=NULL; + } + chk=read_zsreg(c,R0); + write_zsreg(c, R3, c->regs[R3]); + z8530_rtsdtr(c,0); + return 0; +} + + +EXPORT_SYMBOL(z8530_sync_txdma_close); + /* * Describe a Z8530 in a standard format. We must pass the I/O as * the port offset isnt predictable. The main reason for this function @@ -929,7 +1100,12 @@ if(c->tx_skb==NULL) { /* Idle on */ - disable_dma(c->txdma); + if(c->txdma) + { + flags=claim_dma_lock(); + disable_dma(c->txdma); + release_dma_lock(flags); + } c->txcount=0; } else @@ -938,19 +1114,22 @@ c->txcount=c->tx_skb->len; - if(c->tx_dma_used) + if(c->dma_tx) { /* - * FIXME. DMA is broken for the non 85230, + * FIXME. DMA is broken for the original 8530, * on the older parts we need to set a flag and * wait for a further TX interrupt to fire this * stage off */ + + flags=claim_dma_lock(); disable_dma(c->txdma); clear_dma_ff(c->txdma); set_dma_addr(c->txdma, virt_to_bus(c->tx_ptr)); set_dma_count(c->txdma, c->txcount); enable_dma(c->txdma); + release_dma_lock(flags); write_zsreg(c, R5, c->regs[R5]|TxENAB); } else @@ -1020,12 +1199,17 @@ * Save the ready state and the buffer currently * being used as the DMA target */ + int ready=c->dma_ready; - char *rxb=c->rx_buf[c->dma_num]; + unsigned char *rxb=c->rx_buf[c->dma_num]; + unsigned long flags; /* * Complete this DMA. Neccessary to find the length */ + + flags=claim_dma_lock(); + disable_dma(c->rxdma); clear_dma_ff(c->rxdma); c->rxdma_on=0; @@ -1042,16 +1226,21 @@ if(ready) { c->dma_num^=1; - set_dma_mode(c->rxdma, DMA_MODE_READ); + set_dma_mode(c->rxdma, DMA_MODE_READ|0x10); set_dma_addr(c->rxdma, virt_to_bus(c->rx_buf[c->dma_num])); set_dma_count(c->rxdma, c->mtu); c->rxdma_on = 1; enable_dma(c->rxdma); + /* Stop any frames that we missed the head of + from passing */ + write_zsreg(c, R0, RES_Rx_CRC); } else /* Can't occur as we dont reenable the DMA irq until after the flip is done */ printk("DMA flip overrun!\n"); + + release_dma_lock(flags); /* * Shove the old buffer into an sk_buff. We can't DMA @@ -1127,6 +1316,21 @@ printk("Lost a frame\n"); } +/* + * Cannot DMA over a 64K boundary on a PC + */ + +extern inline int spans_boundary(struct sk_buff *skb) +{ + unsigned long a=(unsigned long)skb->data; + a^=(a+skb->len); + if(a&0x00010000) /* If the 64K bit is different.. */ + { + printk("spanner\n"); + return 1; + } + return 0; +} /* * Queue a packet for transmission. Because we have rather @@ -1151,7 +1355,7 @@ * limit, then copy to the flip buffer */ - if(c->dma_tx && (unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024) + if(c->dma_tx && ((unsigned long)(virt_to_bus(skb->data+skb->len))>=16*1024*1024 || spans_boundary(skb))) { /* * Send the flip buffer, and flip the flippy bit. diff -u --recursive --new-file v2.1.125/linux/drivers/net/z85230.h linux/drivers/net/z85230.h --- v2.1.125/linux/drivers/net/z85230.h Wed Sep 9 14:51:08 1998 +++ linux/drivers/net/z85230.h Fri Oct 9 11:56:59 1998 @@ -401,6 +401,8 @@ extern int z8530_sync_close(struct device *, struct z8530_channel *); extern int z8530_sync_dma_open(struct device *, struct z8530_channel *); extern int z8530_sync_dma_close(struct device *, struct z8530_channel *); +extern int z8530_sync_txdma_open(struct device *, struct z8530_channel *); +extern int z8530_sync_txdma_close(struct device *, struct z8530_channel *); extern int z8530_channel_load(struct z8530_channel *, u8 *); extern int z8530_queue_xmit(struct z8530_channel *c, struct sk_buff *skb); extern struct net_device_stats *z8530_get_stats(struct z8530_channel *c); diff -u --recursive --new-file v2.1.125/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v2.1.125/linux/drivers/net/znet.c Thu Feb 12 20:56:09 1998 +++ linux/drivers/net/znet.c Fri Oct 9 11:56:59 1998 @@ -591,6 +591,7 @@ /* The inverse routine to znet_open(). */ static int znet_close(struct device *dev) { + unsigned long flags; int ioaddr = dev->base_addr; dev->tbusy = 1; @@ -598,8 +599,10 @@ outb(CMD0_RESET, ioaddr); /* CMD0_RESET */ + flags=claim_dma_lock(); disable_dma(zn.rx_dma); disable_dma(zn.tx_dma); + release_dma_lock(flags); free_irq(dev->irq, dev); @@ -662,10 +665,14 @@ void show_dma(void) { + unsigned long flags; short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE; unsigned addr = inb(dma_port); addr |= inb(dma_port) << 8; + + flags=claim_dma_lock(); printk("Addr: %04x cnt:%3x...", addr<<1, get_dma_residue(zn.tx_dma)); + release_dma_lock(flags); } /* Initialize the hardware. We have to do this when the board is open()ed @@ -680,22 +687,22 @@ /* Reset the chip, and start it up. */ outb(CMD0_RESET, ioaddr); - cli(); { /* Protect against a DMA flip-flop */ - disable_dma(zn.rx_dma); /* reset by an interrupting task. */ - clear_dma_ff(zn.rx_dma); - set_dma_mode(zn.rx_dma, DMA_RX_MODE); - set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_start); - set_dma_count(zn.rx_dma, RX_BUF_SIZE); - enable_dma(zn.rx_dma); - /* Now set up the Tx channel. */ - disable_dma(zn.tx_dma); - clear_dma_ff(zn.tx_dma); - set_dma_mode(zn.tx_dma, DMA_TX_MODE); - set_dma_addr(zn.tx_dma, (unsigned int) zn.tx_start); - set_dma_count(zn.tx_dma, zn.tx_buf_len<<1); - enable_dma(zn.tx_dma); - } sti(); - + flags=claim_dma_lock(); + disable_dma(zn.rx_dma); /* reset by an interrupting task. */ + clear_dma_ff(zn.rx_dma); + set_dma_mode(zn.rx_dma, DMA_RX_MODE); + set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_start); + set_dma_count(zn.rx_dma, RX_BUF_SIZE); + enable_dma(zn.rx_dma); + /* Now set up the Tx channel. */ + disable_dma(zn.tx_dma); + clear_dma_ff(zn.tx_dma); + set_dma_mode(zn.tx_dma, DMA_TX_MODE); + set_dma_addr(zn.tx_dma, (unsigned int) zn.tx_start); + set_dma_count(zn.tx_dma, zn.tx_buf_len<<1); + enable_dma(zn.tx_dma); + release_dma_lock(flags); + if (znet_debug > 1) printk(KERN_DEBUG "%s: Initializing the i82593, tx buf %p... ", dev->name, zn.tx_start); diff -u --recursive --new-file v2.1.125/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c --- v2.1.125/linux/drivers/pci/oldproc.c Fri Oct 9 13:27:10 1998 +++ linux/drivers/pci/oldproc.c Sun Oct 11 15:46:03 1998 @@ -1,5 +1,5 @@ /* - * $Id: oldproc.c,v 1.20 1998/08/23 12:12:01 mj Exp $ + * $Id: oldproc.c,v 1.24 1998/10/11 15:13:04 mj Exp $ * * Backward-compatible procfs interface for PCI. * @@ -200,6 +200,7 @@ DEVICE( PROMISE, PROMISE_5300, "DC5030"), DEVICE( N9, N9_I128, "Imagine 128"), DEVICE( N9, N9_I128_2, "Imagine 128v2"), + DEVICE( N9, N9_I128_T2R, "Revolution 3D"), DEVICE( UMC, UMC_UM8673F, "UM8673F"), DEVICE( UMC, UMC_UM8891A, "UM8891A"), DEVICE( UMC, UMC_UM8886BF, "UM8886BF"), @@ -528,10 +529,10 @@ DEVICE( ADAPTEC, ADAPTEC_7883, "AIC-7883U"), DEVICE( ADAPTEC, ADAPTEC_7884, "AIC-7884U"), DEVICE( ADAPTEC, ADAPTEC_1030, "ABA-1030 DVB receiver"), - DEVICE( ADAPTEC2, ADAPTEC2_2940U2, "AHA-2940U2"), - DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"), - DEVICE( ADAPTEC2, ADAPTEC2_3940U2, "AHA-3940U2"), - DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"), + DEVICE( ADAPTEC2, ADAPTEC2_2940U2,"AHA-2940U2"), + DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"), + DEVICE( ADAPTEC2, ADAPTEC2_3940U2,"AHA-3940U2"), + DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"), DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL"), DEVICE( TIGERJET, TIGERJET_300, "Tiger300 ISDN"), DEVICE( ARK, ARK_STING, "Stingray"), diff -u --recursive --new-file v2.1.125/linux/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c --- v2.1.125/linux/drivers/pnp/parport_probe.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/pnp/parport_probe.c Fri Oct 9 12:20:27 1998 @@ -91,7 +91,7 @@ int parport_probe(struct parport *port, char *buffer, int len) { - struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, PARPORT_DEV_TRAN, &dev); + struct pardevice *dev = parport_register_device(port, "IEEE 1284 probe", NULL, NULL, NULL, 0, &dev); int result = 0; diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.125/linux/drivers/scsi/Config.in Thu Sep 17 17:53:36 1998 +++ linux/drivers/scsi/Config.in Fri Oct 9 12:20:27 1998 @@ -53,7 +53,7 @@ if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT if [ "$CONFIG_SCSI_PPA" != "n" ]; then - int ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3 + bool ' Pedantic EPP-checking' CONFIG_SCSI_PPA_HAVE_PEDANTIC fi dep_tristate 'IOMEGA ZIP Plus drive SCSI support' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT fi diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c --- v2.1.125/linux/drivers/scsi/NCR53c406a.c Thu May 14 19:47:40 1998 +++ linux/drivers/scsi/NCR53c406a.c Fri Oct 9 11:56:59 1998 @@ -317,15 +317,14 @@ if ((count & 1) || (((unsigned) ptr) & 1)) panic ("NCR53c406a: attempted unaligned DMA transfer\n"); - save_flags(flags); - cli(); + flags=claim_dma_lock(); disable_dma(dma_chan); clear_dma_ff(dma_chan); set_dma_addr(dma_chan, (long) ptr); set_dma_count(dma_chan, count); set_dma_mode(dma_chan, mode); enable_dma(dma_chan); - restore_flags(flags); + release_dma_lock(flags); return count; } @@ -343,12 +342,12 @@ static __inline__ int NCR53c406a_dma_residual (void) { register int tmp; - unsigned long flags = 0; - save_flags(flags); - cli(); + unsigned long flags; + + flags=claim_dma_lock(); clear_dma_ff(dma_chan); tmp = get_dma_residue(dma_chan); - restore_flags(flags); + release_dma_lock(flags); return tmp; } diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/README.aic7xxx linux/drivers/scsi/README.aic7xxx --- v2.1.125/linux/drivers/scsi/README.aic7xxx Fri Oct 9 13:27:10 1998 +++ linux/drivers/scsi/README.aic7xxx Fri Oct 9 11:56:59 1998 @@ -412,7 +412,7 @@ the system. Each file presents the current configuration and transfer statistics (enabled with #define in aic7xxx.c) for each controller. - Thanks to Michael Neuffer for for his upper-level SCSI help, and + Thanks to Michael Neuffer for his upper-level SCSI help, and Matthew Jacob for statistics support. Debugging the driver diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.1.125/linux/drivers/scsi/aha152x.c Wed Sep 9 14:51:08 1998 +++ linux/drivers/scsi/aha152x.c Fri Oct 9 11:38:15 1998 @@ -444,6 +444,7 @@ /* set by aha152x_setup according to the command line */ static int setup_count=0; +static int registered_count=0; static struct aha152x_setup { int io_port; int irq; @@ -951,6 +952,7 @@ shpnt = aha152x_host[setup[i].irq-IRQ_MIN] = scsi_register(tpnt, sizeof(struct aha152x_hostdata)); + registered_count++; shpnt->io_port = setup[i].io_port; shpnt->n_io_port = IO_RANGE; @@ -1013,7 +1015,7 @@ SETBITS(DMACNTRL0, INTEN); - ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", NULL); + ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", shpnt); if(ok<0) { if(ok == -EINVAL) printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq); @@ -1024,6 +1026,8 @@ printk("aha152x: driver needs an IRQ.\n"); scsi_unregister(shpnt); + registered_count--; + release_region(shpnt->io_port, IO_RANGE); shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; continue; } @@ -1037,7 +1041,7 @@ while(!HOSTDATA(shpnt)->swint && jiffiesirq,0); + free_irq(shpnt->irq,shpnt); if(!HOSTDATA(shpnt)->swint) { if(TESTHI(DMASTAT, INTSTAT)) { @@ -1049,6 +1053,8 @@ printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq); scsi_unregister(shpnt); + registered_count--; + release_region(shpnt->io_port, IO_RANGE); shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; continue; } @@ -1061,12 +1067,23 @@ SETPORT(SSTAT0, 0x7f); SETPORT(SSTAT1, 0xef); - if(request_irq(shpnt->irq,aha152x_intr,SA_INTERRUPT,"aha152x",NULL)<0) { + if(request_irq(shpnt->irq,aha152x_intr,SA_INTERRUPT,"aha152x",shpnt)<0) { printk("aha152x: failed to reassign interrupt.\n"); } } - return (setup_count>0); + return (registered_count>0); +} + + +int aha152x_release(struct Scsi_Host *shpnt) +{ + if (shpnt->irq) + free_irq(shpnt->irq, shpnt); + if (shpnt->io_port) + release_region(shpnt->io_port, IO_RANGE); + + return 0; } /* diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h --- v2.1.125/linux/drivers/scsi/aha152x.h Fri Jul 31 17:08:24 1998 +++ linux/drivers/scsi/aha152x.h Fri Oct 16 15:43:12 1998 @@ -36,6 +36,7 @@ queuecommand: aha152x_queue, \ abort: aha152x_abort, \ reset: aha152x_reset, \ + release: aha152x_release, \ slave_attach: 0, \ bios_param: aha152x_biosparam, \ can_queue: 1, \ diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/aic7xxx/bsd_q.h linux/drivers/scsi/aic7xxx/bsd_q.h --- v2.1.125/linux/drivers/scsi/aic7xxx/bsd_q.h Fri Oct 9 13:27:10 1998 +++ linux/drivers/scsi/aic7xxx/bsd_q.h Wed Dec 31 16:00:00 1969 @@ -1,507 +0,0 @@ -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $Id: queue.h,v 1.21 1998/05/12 03:55:25 gibbs Exp $ - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -/* - * This file defines five types of data structures: singly-linked lists, - * slingly-linked tail queues, lists, tail queues, and circular queues. - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A singly-linked tail queue is headed by a pair of pointers, one to the - * head of the list and the other to the tail of the list. The elements are - * singly linked for minimum space and pointer manipulation overhead at the - * expense of O(n) removal for arbitrary elements. New elements can be added - * to the list after an existing element, at the head of the list, or at the - * end of the list. Elements being removed from the head of the tail queue - * should use the explicit macro for this purpose for optimum efficiency. - * A singly-linked tail queue may only be traversed in the forward direction. - * Singly-linked tail queues are ideal for applications with large datasets - * and few or no removals or for implementing a FIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may only be traversed in the forward direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - * - * - * SLIST LIST STAILQ TAILQ CIRCLEQ - * _HEAD + + + + + - * _ENTRY + + + + + - * _INIT + + + + + - * _EMPTY + + + + + - * _FIRST + + - + + - * _NEXT + + - + + - * _PREV - - - + + - * _LAST - - - + + - * _FOREACH + + - + - - * _INSERT_HEAD + + + + + - * _INSERT_BEFORE - + - + + - * _INSERT_AFTER + + + + + - * _INSERT_TAIL - - + + + - * _REMOVE_HEAD + - + - - - * _REMOVE + + + + + - * - */ - -/* - * Singly-linked List definitions. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List functions. - */ -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) - -#define SLIST_FIRST(head) ((head)->slh_first) - -#define SLIST_FOREACH(var, head, field) \ - for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) - -#define SLIST_INIT(head) { \ - (head)->slh_first = NULL; \ -} - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - (elm)->field.sle_next = (slistelm)->field.sle_next; \ - (slistelm)->field.sle_next = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.sle_next = (head)->slh_first; \ - (head)->slh_first = (elm); \ -} while (0) - -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - (head)->slh_first = (head)->slh_first->field.sle_next; \ -} while (0) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - if ((head)->slh_first == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = (head)->slh_first; \ - while( curelm->field.sle_next != (elm) ) \ - curelm = curelm->field.sle_next; \ - curelm->field.sle_next = \ - curelm->field.sle_next->field.sle_next; \ - } \ -} while (0) - -/* - * Singly-linked Tail queue definitions. - */ -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first;/* first element */ \ - struct type **stqh_last;/* addr of last next element */ \ -} - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) - -#define STAILQ_INIT(head) do { \ - (head)->stqh_first = NULL; \ - (head)->stqh_last = &(head)->stqh_first; \ -} while (0) - -#define STAILQ_FIRST(head) ((head)->stqh_first) -#define STAILQ_LAST(head) (*(head)->stqh_last) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ - (head)->stqh_last = &(elm)->field.stqe_next; \ - (head)->stqh_first = (elm); \ -} while (0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.stqe_next = NULL; \ - *(head)->stqh_last = (elm); \ - (head)->stqh_last = &(elm)->field.stqe_next; \ -} while (0) - -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ - if (((elm)->field.stqe_next = (tqelm)->field.stqe_next) == NULL)\ - (head)->stqh_last = &(elm)->field.stqe_next; \ - (tqelm)->field.stqe_next = (elm); \ -} while (0) - -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if (((head)->stqh_first = \ - (head)->stqh_first->field.stqe_next) == NULL) \ - (head)->stqh_last = &(head)->stqh_first; \ -} while (0) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - if ((head)->stqh_first == (elm)) { \ - STAILQ_REMOVE_HEAD(head, field); \ - } \ - else { \ - struct type *curelm = (head)->stqh_first; \ - while( curelm->field.stqe_next != (elm) ) \ - curelm = curelm->field.stqe_next; \ - if((curelm->field.stqe_next = \ - curelm->field.stqe_next->field.stqe_next) == NULL) \ - (head)->stqh_last = &(curelm)->field.stqe_next; \ - } \ -} while (0) - -/* - * List definitions. - */ - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ - -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_FOREACH(var, head, field) \ - for((var) = (head)->lh_first; (var); (var) = (var)->field.le_next) - -#define LIST_INIT(head) do { \ - (head)->lh_first = NULL; \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - (elm)->field.le_next = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &(elm)->field.le_next; \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} while (0) - -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_REMOVE(elm, field) do { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ -} while (0) - -/* - * Tail queue definitions. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} - -/* - * Tail queue functions. - */ -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FOREACH(var, head, field) \ - for (var = TAILQ_FIRST(head); var; var = TAILQ_NEXT(var, field)) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#define TAILQ_INIT(head) do { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (head)->tqh_first->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.tqe_next = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - (elm)->field.tqe_next = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ -} while (0) - -#define TAILQ_REMOVE(head, elm, field) do { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ -} while (0) - -/* - * Circular queue definitions. - */ -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue functions. - */ -#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) - -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for((var) = (head)->cqh_first; \ - (var) != (void *)(head); \ - (var) = (var)->field.cqe_next) - -#define CIRCLEQ_INIT(head) do { \ - (head)->cqh_first = (void *)(head); \ - (head)->cqh_last = (void *)(head); \ -} while (0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == (void *)(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == (void *)(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = (void *)(head); \ - if ((head)->cqh_last == (void *)(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - (elm)->field.cqe_next = (void *)(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == (void *)(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ -} while (0) - -#define CIRCLEQ_LAST(head) ((head)->cqh_last) - -#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next) - -#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev) - -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - if ((elm)->field.cqe_next == (void *)(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = \ - (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == (void *)(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = \ - (elm)->field.cqe_next; \ -} while (0) - -#ifdef KERNEL - -/* - * XXX insque() and remque() are an old way of handling certain queues. - * They bogusly assumes that all queue heads look alike. - */ - -struct quehead { - struct quehead *qh_link; - struct quehead *qh_rlink; -}; - -#ifdef __GNUC__ - -static __inline void -insque(void *a, void *b) -{ - struct quehead *element = a, *head = b; - - element->qh_link = head->qh_link; - element->qh_rlink = head; - head->qh_link = element; - element->qh_link->qh_rlink = element; -} - -static __inline void -remque(void *a) -{ - struct quehead *element = a; - - element->qh_link->qh_rlink = element->qh_rlink; - element->qh_rlink->qh_link = element->qh_link; - element->qh_rlink = 0; -} - -#else /* !__GNUC__ */ - -void insque __P((void *a, void *b)); -void remque __P((void *a)); - -#endif /* __GNUC__ */ - -#endif /* KERNEL */ - -#endif /* !_SYS_QUEUE_H_ */ diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/aic7xxx/sequencer.h linux/drivers/scsi/aic7xxx/sequencer.h --- v2.1.125/linux/drivers/scsi/aic7xxx/sequencer.h Fri Oct 9 13:27:10 1998 +++ linux/drivers/scsi/aic7xxx/sequencer.h Fri Oct 9 11:37:17 1998 @@ -73,7 +73,9 @@ union ins_formats format; unsigned int srcline; struct symbol *patch_label; - STAILQ_ENTRY(instruction) links; + struct { + struct instruction *stqe_next; + } links; }; #define AIC_OP_OR 0x0 diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.1.125/linux/drivers/scsi/aic7xxx.c Fri Oct 9 13:27:10 1998 +++ linux/drivers/scsi/aic7xxx.c Sat Oct 10 09:30:16 1998 @@ -328,7 +328,6 @@ #include "hosts.h" #include "aic7xxx.h" -#include "aic7xxx/bsd_q.h" #include "aic7xxx/sequencer.h" #include "aic7xxx/scsi_message.h" #include "aic7xxx_reg.h" @@ -350,7 +349,7 @@ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#define AIC7XXX_C_VERSION "5.1.0" +#define AIC7XXX_C_VERSION "5.1.2" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -6281,8 +6280,10 @@ (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0))); if (aic7xxx_panic_on_abort) aic7xxx_panic_abort(p, NULL); +#ifdef CONFIG_PCI if (errno & PCIERRSTAT) aic7xxx_pci_intr(p); +#endif if (errno & (SQPARERR | ILLOPCODE | ILLSADDR)) { sti(); diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.1.125/linux/drivers/scsi/eata.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/scsi/eata.c Fri Oct 9 11:56:59 1998 @@ -1034,12 +1034,17 @@ if (HD(j)->subversion == ESA) sh[j]->unchecked_isa_dma = FALSE; else { + unsigned long flags; sh[j]->wish_block = TRUE; sh[j]->unchecked_isa_dma = TRUE; + + flags=claim_dma_lock(); disable_dma(dma_channel); clear_dma_ff(dma_channel); set_dma_mode(dma_channel, DMA_MODE_CASCADE); enable_dma(dma_channel); + release_dma_lock(flags); + } strcpy(BN(j), name); diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v2.1.125/linux/drivers/scsi/fdomain.c Sun Jul 26 11:57:16 1998 +++ linux/drivers/scsi/fdomain.c Wed Oct 14 11:43:14 1998 @@ -107,6 +107,7 @@ 2.0.12 5.44 8 Aug 1996 Use ID 7 for all PCI cards 2.1.1 5.45 2 Oct 1996 Update ROM accesses for 2.1.x 2.1.97 5.46 23 Apr 1998 Rewritten PCI detection routines [mj] + 2.1.11x 5.47 9 Aug 1998 Touched for 8 SCSI disk majors support @@ -1891,7 +1892,11 @@ 0x0a bytes long. Heads are one less than we need to report. */ - drive = MINOR(dev) / 16; + if (MAJOR(dev) != SCSI_DISK0_MAJOR) { + printk("fdomain_16x0_biosparam: too many disks"); + return 0; + } + drive = MINOR(dev) >> 4; if (bios_major == 2) { switch (Quantum) { diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c --- v2.1.125/linux/drivers/scsi/imm.c Mon Sep 28 10:51:34 1998 +++ linux/drivers/scsi/imm.c Fri Oct 9 12:20:27 1998 @@ -172,14 +172,29 @@ imm_hosts[i].dev = parport_register_device(pb, "imm", NULL, imm_wakeup, - NULL, PARPORT_DEV_TRAN, (void *) &imm_hosts[i]); + NULL, 0, (void *) &imm_hosts[i]); + + if (!imm_hosts[i].dev) + continue; /* Claim the bus so it remembers what we do to the control * registers. [ CTR and ECP ] */ - if (imm_pb_claim(i)) - while (imm_hosts[i].p_busy) - schedule(); /* We are safe to schedule here */ + if (imm_pb_claim(i)) + { + unsigned long now = jiffies; + while (imm_hosts[i].p_busy) + { + schedule(); /* We are safe to schedule here */ + if (jiffies > now + 3*HZ) + { + printk(KERN_ERR "imm%d: failed to claim parport because a " + "pardevice is owning the port for too longtime!\n", + i); + return 0; + } + } + } ppb = IMM_BASE(i) = imm_hosts[i].dev->port->base; w_ctr(ppb, 0x0c); diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c --- v2.1.125/linux/drivers/scsi/ppa.c Mon Sep 28 10:51:34 1998 +++ linux/drivers/scsi/ppa.c Fri Oct 9 12:20:27 1998 @@ -133,14 +133,29 @@ ppa_hosts[i].dev = parport_register_device(pb, "ppa", NULL, ppa_wakeup, - NULL, PARPORT_DEV_TRAN, (void *) &ppa_hosts[i]); + NULL, 0, (void *) &ppa_hosts[i]); + + if (!ppa_hosts[i].dev) + continue; /* Claim the bus so it remembers what we do to the control * registers. [ CTR and ECP ] */ if (ppa_pb_claim(i)) + { + unsigned long now = jiffies; while (ppa_hosts[i].p_busy) + { schedule(); /* We are safe to schedule here */ + if (jiffies > now + 3*HZ) + { + printk(KERN_ERR "ppa%d: failed to claim parport because a " + "pardevice is owning the port for too longtime!\n", + i); + return 0; + } + } + } ppb = PPA_BASE(i) = ppa_hosts[i].dev->port->base; w_ctr(ppb, 0x0c); diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.125/linux/drivers/scsi/scsi.c Fri Oct 9 13:27:11 1998 +++ linux/drivers/scsi/scsi.c Wed Oct 14 11:43:13 1998 @@ -1734,8 +1734,7 @@ host_active = NULL; /* For block devices "wake_up" is done in end_scsi_request */ - if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR && - MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) { + if (!SCSI_BLK_MAJOR(SCpnt->request.rq_dev)) { struct Scsi_Host * next; for (next = host->block; next != host; next = next->block) diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.1.125/linux/drivers/scsi/scsi.h Thu Sep 17 17:53:36 1998 +++ linux/drivers/scsi/scsi.h Fri Oct 16 15:43:09 1998 @@ -690,16 +690,22 @@ * that an interrupt may start another request, so we run this with interrupts * turned off */ -#define INIT_SCSI_REQUEST \ - if (!CURRENT) { \ - CLEAR_INTR; \ - return; \ - } \ - 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"); \ +#if MAJOR_NR == SCSI_DISK0_MAJOR +#define CHECK_INITREQ_SD_MAJOR(major) SCSI_DISK_MAJOR(major) +#else +#define CHECK_INITREQ_SD_MAJOR(major) ((major) == MAJOR_NR) +#endif + +#define INIT_SCSI_REQUEST \ + if (!CURRENT) { \ + CLEAR_INTR; \ + return; \ + } \ + if (!CHECK_INITREQ_SD_MAJOR(MAJOR(CURRENT->rq_dev)))\ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { \ + if (!buffer_locked(CURRENT->bh)) \ + panic(DEVICE_NAME ": block not locked"); \ } #endif diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- v2.1.125/linux/drivers/scsi/scsi_debug.c Wed Sep 9 14:51:09 1998 +++ linux/drivers/scsi/scsi_debug.c Wed Oct 14 11:43:13 1998 @@ -42,8 +42,8 @@ /* A few options that we want selected */ -#define NR_HOSTS_PRESENT 1 -#define NR_FAKE_DISKS 3 +#define NR_HOSTS_PRESENT 20 +#define NR_FAKE_DISKS 6 #define N_HEAD 32 #define N_SECTOR 64 #define DISK_READONLY(TGT) (1) @@ -55,6 +55,8 @@ /* Skip some consistency checking. Good for benchmarking */ #define SPEEDY +/* Read return zeros. Undefine for benchmarking */ +#define CLEAR /* Number of real scsi disks that will be detected ahead of time */ static int NR_REAL=-1; @@ -299,11 +301,8 @@ #if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE) { int delay = SCSI_SETUP_LATENCY; - double usec; - usec = 0.0; - usec = (SCpnt->request.nr_sectors << 9) * 1.0e6 / SCSI_DATARATE; - delay += usec; + delay += SCpnt->request.nr_sectors * SCSI_DATARATE; if(delay) usleep(delay); }; #endif @@ -323,29 +322,31 @@ do{ VERIFY1_DEBUG(READ); /* For the speedy test, we do not even want to fill the buffer with anything */ -#ifndef SPEEDY +#ifdef CLEAR memset(buff, 0, bufflen); #endif /* If this is block 0, then we want to read the partition table for this * device. Let's make one up */ - if(block == 0 && target == 0) { + if(block == 0) { + int i; memset(buff, 0, bufflen); *((unsigned short *) (buff+510)) = 0xAA55; p = (struct partition* ) (buff + 0x1be); - npart = 0; - while(starts[npart+1]){ - p->start_sect = starts[npart]; - p->nr_sects = starts[npart+1] - starts [npart]; + i = 0; + while(starts[i+1]){ + p->start_sect = starts[i]; + p->nr_sects = starts[i+1] - starts [i]; p->sys_ind = 0x81; /* Linux partition */ - p->head = (npart == 0 ? 1 : 0); + p->head = (i == 0 ? 1 : 0); p->sector = 1; - p->cyl = starts[npart] / N_HEAD / N_SECTOR; + p->cyl = starts[i] / N_HEAD / N_SECTOR; p->end_head = N_HEAD - 1; p->end_sector = N_SECTOR; - p->end_cyl = starts[npart + 1] / N_HEAD / N_SECTOR; + p->end_cyl = starts[i + 1] / N_HEAD / N_SECTOR; p++; - npart++; + i++; }; + if (!npart) npart = i; scsi_debug_errsts = 0; break; }; @@ -376,7 +377,7 @@ } /* End phony disk change code */ #endif -#ifndef SPEEDY +#ifdef CLEAR memcpy(buff, &target, sizeof(target)); memcpy(buff+sizeof(target), cmd, 24); memcpy(buff+60, &block, sizeof(block)); @@ -384,7 +385,7 @@ #endif nbytes -= bufflen; if(SCpnt->use_sg){ -#ifndef SPEEDY +#ifdef CLEAR memcpy(buff+128, bh, sizeof(struct buffer_head)); #endif block += bufflen >> 9; diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.1.125/linux/drivers/scsi/scsi_obsolete.c Fri Oct 9 13:27:11 1998 +++ linux/drivers/scsi/scsi_obsolete.c Wed Oct 14 11:43:13 1998 @@ -658,8 +658,7 @@ host_active = NULL; /* For block devices "wake_up" is done in end_scsi_request */ - if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR && - MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) { + if (!SCSI_BLK_MAJOR(SCpnt->request.rq_dev)) { struct Scsi_Host * next; for (next = host->block; next != host; next = next->block) diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.1.125/linux/drivers/scsi/sd.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/scsi/sd.c Wed Oct 14 11:43:13 1998 @@ -14,8 +14,11 @@ * * Modified by Eric Youngdale eric@aib.com to support loadable * low-level scsi drivers. + * + * Modified by Jirka Hanika geo@ff.cuni.cz to support more + * scsi disks using eight major numbers. */ - + #include #ifdef MODULE /* @@ -41,7 +44,7 @@ #include #include -#define MAJOR_NR SCSI_DISK_MAJOR +#define MAJOR_NR SCSI_DISK0_MAJOR #include #include "scsi.h" #include "hosts.h" @@ -54,6 +57,15 @@ /* * static const char RCSid[] = "$Header:"; */ + +#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i)) + +#define SCSI_DISKS_PER_MAJOR 16 +#define SD_MAJOR_NUMBER(i) SD_MAJOR((i) >> 8) +#define SD_MINOR_NUMBER(i) ((i) & 255) +#define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), (i) & 255) +#define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4) +#define N_USED_SD_MAJORS ((sd_template.dev_max + SCSI_DISKS_PER_MAJOR - 1) / SCSI_DISKS_PER_MAJOR) #define MAX_RETRIES 5 @@ -91,12 +103,9 @@ static void sd_devname(unsigned int disknum, char * buffer) { - if( disknum <= 26 ) - { + if( disknum < 26 ) sprintf(buffer, "sd%c", 'a' + disknum); - } - else - { + else { unsigned int min1; unsigned int min2; /* @@ -105,13 +114,13 @@ */ min1 = disknum / 26; min2 = disknum % 26; - sprintf(buffer, "sd%c%c", 'a' + min1, 'a' + min2); + sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); } } struct Scsi_Device_Template sd_template = { NULL, "disk", "sd", NULL, TYPE_DISK, - SCSI_DISK_MAJOR, 0, 0, 0, 1, + SCSI_DISK0_MAJOR, 0, 0, 0, 1, sd_detect, sd_init, sd_finish, sd_attach, sd_detach }; @@ -175,7 +184,7 @@ * See if we are requesting a non-existent partition. Do this * after checking for disk change. */ - if(sd_sizes[MINOR(inode->i_rdev)] == 0) + if(sd_sizes[SD_PARTITION(inode->i_rdev)] == 0) return -ENXIO; if(rscsi_disks[target].device->removable) @@ -230,8 +239,13 @@ fop_revalidate_scsidisk /* revalidate */ }; +/* + * If we need more than one SCSI disk major (i.e. more than + * 16 SCSI disks), we'll have to kmalloc() more gendisks later. + */ + static struct gendisk sd_gendisk = { - MAJOR_NR, /* Major number */ + SCSI_DISK0_MAJOR, /* Major number */ "sd", /* Major name */ 4, /* Bits to shift to get real from partition */ 1 << 4, /* Number of partitions per real */ @@ -242,7 +256,12 @@ 0, /* number */ NULL, /* internal */ NULL /* next */ -}; +}; + +static struct gendisk *sd_gendisks = &sd_gendisk; + +#define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR] +#define LAST_SD_GENDISK sd_gendisks[N_USED_SD_MAJORS - 1] static void sd_geninit (struct gendisk *ignored) { @@ -251,10 +270,6 @@ for (i = 0; i < sd_template.dev_max; ++i) if(rscsi_disks[i].device) sd[i << 4].nr_sects = rscsi_disks[i].capacity; -#if 0 - /* No longer needed - we keep track of this as we attach/detach */ - sd_gendisk.nr_real = sd_template.dev_max; -#endif } /* @@ -271,7 +286,7 @@ int good_sectors = (result == 0 ? this_count : 0); int block_sectors = 1; - sd_devname(MINOR(SCpnt->request.rq_dev) >> 4, nbuff); + sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff); SCSI_LOG_HLCOMPLETE(1,printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff, SCpnt->host->host_no, @@ -309,7 +324,7 @@ } else if (sector_size == 256) error_sector >>= 1; - error_sector -= sd[MINOR(SCpnt->request.rq_dev)].start_sect; + error_sector -= sd[SD_PARTITION(SCpnt->request.rq_dev)].start_sect; error_sector &= ~ (block_sectors - 1); good_sectors = error_sector - SCpnt->request.sector; if (good_sectors < 0 || good_sectors >= this_count) @@ -524,7 +539,7 @@ } INIT_SCSI_REQUEST; - SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device; + SDev = rscsi_disks[CURRENT_DEV].device; /* * If the host for this device is in error recovery mode, don't @@ -578,7 +593,7 @@ if (flag++ == 0) SCpnt = scsi_allocate_device(&CURRENT, - rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0); + rscsi_disks[CURRENT_DEV].device, 0); else SCpnt = NULL; /* @@ -643,7 +658,7 @@ return; } - devm = MINOR(SCpnt->request.rq_dev); + devm = SD_PARTITION(SCpnt->request.rq_dev); dev = DEVICE_NR(SCpnt->request.rq_dev); block = SCpnt->request.sector; @@ -1329,7 +1344,7 @@ printk ("scsi : deleting disk entry.\n"); rscsi_disks[i].device = NULL; sd_template.nr_dev--; - sd_gendisk.nr_real--; + SD_GENDISK(i).nr_real--; /* Wake up a process waiting for device */ wake_up(&SCpnt->device->device_wait); @@ -1463,67 +1478,99 @@ if (sd_template.dev_noticed == 0) return 0; + if (!rscsi_disks) + sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS; + + /* 128 disks is our current limit (8 majors, 16 disks per major) */ + if(sd_template.dev_max > 128) + sd_template.dev_max = 128; + if(!sd_registered) { - if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) { - printk("Unable to get major %d for SCSI disk\n",MAJOR_NR); - return 1; - } - sd_registered++; - } + for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++) { + if (register_blkdev(SD_MAJOR(i),"sd",&sd_fops)) { + printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i)); + return 1; + } + } + sd_registered++; + } /* We do not support attaching loadable devices yet. */ if(rscsi_disks) return 0; - sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS; - rscsi_disks = (Scsi_Disk *) scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC); memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk)); - - sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * - sizeof(int), GFP_ATOMIC); + + /* for every (necessary) major: */ + sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int)); - sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * - sizeof(int), GFP_ATOMIC); - - sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * - sizeof(int), GFP_ATOMIC); + sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); + sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC); - for(i=0;i<(sd_template.dev_max << 4);i++) - { - sd_blocksizes[i] = 1024; - sd_hardsizes[i] = 512; - } + for(i=0; i < sd_template.dev_max << 4; i++) { + sd_blocksizes[i] = 1024; + sd_hardsizes[i] = 512; + } - blksize_size[MAJOR_NR] = sd_blocksizes; - hardsect_size[MAJOR_NR] = sd_hardsizes; + for (i=0; i < N_USED_SD_MAJORS; i++) { + blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4); + hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4); + } sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(struct hd_struct), GFP_ATOMIC); - - sd_gendisk.max_nr = sd_template.dev_max; - sd_gendisk.part = sd; - sd_gendisk.sizes = sd_sizes; - sd_gendisk.real_devices = (void *) rscsi_disks; + if (N_USED_SD_MAJORS > 1) + sd_gendisks = (struct gendisk *) + kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC); + for (i=0; i < N_USED_SD_MAJORS; i++) { + sd_gendisks[i].major = SD_MAJOR(i); + sd_gendisks[i].major_name = "sd"; + sd_gendisks[i].minor_shift = 4; + sd_gendisks[i].max_p = 1 << 4; + sd_gendisks[i].max_nr = SCSI_DISKS_PER_MAJOR; + sd_gendisks[i].init = sd_geninit; + sd_gendisks[i].part = sd + (i * SCSI_DISKS_PER_MAJOR << 4); + sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4); + sd_gendisks[i].nr_real = 0; + sd_gendisks[i].next = sd_gendisks + i + 1; + sd_gendisks[i].real_devices = + (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR); + } + LAST_SD_GENDISK.max_nr = + sd_template.dev_max % SCSI_DISKS_PER_MAJOR; + LAST_SD_GENDISK.next = NULL; return 0; } +/* + * sd_get_queue() returns the queue which corresponds to a given device. + */ +static struct request **sd_get_queue (kdev_t dev) +{ + return &blk_dev[MAJOR_NR].current_request; +} + static void sd_finish() { struct gendisk *gendisk; int i; - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++) { + /* FIXME: After 2.2 we should implement multiple sd queues */ + blk_dev[SD_MAJOR(i)].request_fn = DEVICE_REQUEST; + if (i) blk_dev[SD_MAJOR(i)].queue = sd_get_queue; + } for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next) - if (gendisk == &sd_gendisk) + if (gendisk == sd_gendisks) break; if (gendisk == NULL) { - sd_gendisk.next = gendisk_head; - gendisk_head = &sd_gendisk; + LAST_SD_GENDISK.next = gendisk_head; + gendisk_head = sd_gendisks; } for (i = 0; i < sd_template.dev_max; ++i) @@ -1534,7 +1581,7 @@ && !rscsi_disks[i].has_part_table) { sd_sizes[i << 4] = rscsi_disks[i].capacity; /* revalidate does sd_init_onedisk via MAYBE_REINIT*/ - revalidate_scsidisk(MKDEV(MAJOR_NR, i << 4), 0); + revalidate_scsidisk(MKDEV_SD(i), 0); } else i=sd_init_onedisk(i); @@ -1542,13 +1589,17 @@ } /* If our host adapter is capable of scatter-gather, then we increase - * the read-ahead to 16 blocks (32 sectors). If not, we use - * a two block (4 sector) read ahead. + * the read-ahead to 60 blocks (120 sectors). If not, we use + * a two block (4 sector) read ahead. We can only respect this with the + * granularity of every 16 disks (one device major). */ - if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize) - read_ahead[MAJOR_NR] = 120; /* 120 sector read-ahead */ - else - read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ + for (i=0; i < N_USED_SD_MAJORS; i++) { + read_ahead[SD_MAJOR(i)] = + (rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device + && rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device->host->sg_tablesize) + ? 120 /* 120 sector read-ahead */ + : 4; /* 4 sector read-ahead */ + } return; } @@ -1586,7 +1637,7 @@ rscsi_disks[i].device = SDp; rscsi_disks[i].has_part_table = 0; sd_template.nr_dev++; - sd_gendisk.nr_real++; + SD_GENDISK(i).nr_real++; return 0; } @@ -1594,7 +1645,6 @@ #define USAGE rscsi_disks[target].device->access_count #define CAPACITY rscsi_disks[target].capacity #define MAYBE_REINIT sd_init_onedisk(target) -#define GENDISK_STRUCT sd_gendisk /* This routine is called to flush all partitions and partition tables * for a changed scsi disk, and then re-read the new partition table. @@ -1603,15 +1653,13 @@ * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. */ -int revalidate_scsidisk(kdev_t dev, int maxusage){ +int revalidate_scsidisk(kdev_t dev, int maxusage) { int target; - struct gendisk * gdev; int max_p; int start; int i; target = DEVICE_NR(dev); - gdev = &GENDISK_STRUCT; if (DEVICE_BUSY || USAGE > maxusage) { printk("Device busy for revalidation (usage=%d)\n", USAGE); @@ -1619,37 +1667,38 @@ } DEVICE_BUSY = 1; - max_p = gdev->max_p; - start = target << gdev->minor_shift; + max_p = sd_gendisks->max_p; + start = target << sd_gendisks->minor_shift; for (i=max_p - 1; i >=0 ; i--) { - int minor = start+i; - kdev_t devi = MKDEV(MAJOR_NR, minor); + int index = start+i; + kdev_t devi = MKDEV_SD_PARTITION(index); struct super_block *sb = get_super(devi); sync_dev(devi); if (sb) invalidate_inodes(sb); invalidate_buffers(devi); - gdev->part[minor].start_sect = 0; - gdev->part[minor].nr_sects = 0; + sd_gendisks->part[index].start_sect = 0; + sd_gendisks->part[index].nr_sects = 0; /* * Reset the blocksize for everything so that we can read * the partition table. Technically we will determine the * correct block size when we revalidate, but we do this just * to make sure that everything remains consistent. */ - blksize_size[MAJOR_NR][minor] = 1024; + sd_blocksizes[index] = 1024; if( rscsi_disks[target].sector_size == 2048 ) - blksize_size[MAJOR_NR][minor] = 2048; + sd_blocksizes[index] = 2048; else - blksize_size[MAJOR_NR][minor] = 1024; + sd_blocksizes[index] = 1024; } #ifdef MAYBE_REINIT MAYBE_REINIT; #endif - gdev->part[start].nr_sects = CAPACITY; - resetup_one_dev(gdev, target); + sd_gendisks->part[start].nr_sects = CAPACITY; + resetup_one_dev(&SD_GENDISK(target), + target % SCSI_DISKS_PER_MAJOR); DEVICE_BUSY = 0; return 0; @@ -1676,15 +1725,15 @@ start = i << sd_gendisk.minor_shift; for (i=max_p - 1; i >=0 ; i--) { - int minor = start+i; - kdev_t devi = MKDEV(MAJOR_NR, minor); + int index = start+i; + kdev_t devi = MKDEV_SD_PARTITION(index); struct super_block *sb = get_super(devi); sync_dev(devi); if (sb) invalidate_inodes(sb); invalidate_buffers(devi); - sd_gendisk.part[minor].start_sect = 0; - sd_gendisk.part[minor].nr_sects = 0; - sd_sizes[minor] = 0; + sd_gendisks->part[index].start_sect = 0; + sd_gendisks->part[index].nr_sects = 0; + sd_sizes[index] = 0; } dpnt->has_part_table = 0; @@ -1693,7 +1742,7 @@ SDp->attached--; sd_template.dev_noticed--; sd_template.nr_dev--; - sd_gendisk.nr_real--; + SD_GENDISK(start).nr_real--; return; } return; @@ -1710,48 +1759,48 @@ { struct gendisk * prev_sdgd; struct gendisk * sdgd; + int i; + int removed = 0; scsi_unregister_module(MODULE_SCSI_DEV, &sd_template); - unregister_blkdev(SCSI_DISK_MAJOR, "sd"); + + for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++) + unregister_blkdev(SD_MAJOR(i),"sd"); + sd_registered--; if( rscsi_disks != NULL ) { - scsi_init_free((char *) rscsi_disks, - (sd_template.dev_noticed + SD_EXTRA_DEVS) - * sizeof(Scsi_Disk)); - + scsi_init_free((char *) rscsi_disks, + sd_template.dev_max * sizeof(Scsi_Disk)); scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int)); scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int)); scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int)); scsi_init_free((char *) sd, (sd_template.dev_max << 4) * sizeof(struct hd_struct)); /* - * Now remove sd_gendisk from the linked list + * Now remove sd_gendisks from the linked list */ - sdgd = gendisk_head; - prev_sdgd = NULL; - while(sdgd != &sd_gendisk) - { - prev_sdgd = sdgd; - sdgd = sdgd->next; - } - if(sdgd != &sd_gendisk) - printk("sd_gendisk not in disk chain.\n"); - else { - if(prev_sdgd != NULL) - prev_sdgd->next = sdgd->next; - else - gendisk_head = sdgd->next; - } + for (sdgd = gendisk_head; sdgd; sdgd = sdgd->next) + { + if (sdgd->next >= sd_gendisks && sdgd->next <= LAST_SD_GENDISK) + removed++, sdgd->next = sdgd->next->next; + else sdgd = sdgd->next; + } + if (removed != N_USED_SCSI_DISKS) + printk("%s %d sd_gendisks in disk chain", + removed > N_USED_SCSI_DISKS ? "total" : "just", removed); + } - blksize_size[MAJOR_NR] = NULL; - blk_dev[MAJOR_NR].request_fn = NULL; - blk_size[MAJOR_NR] = NULL; - hardsect_size[MAJOR_NR] = NULL; - read_ahead[MAJOR_NR] = 0; + for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++) { + blk_dev[SD_MAJOR(i)].request_fn = NULL; + blk_size[SD_MAJOR(i)] = NULL; + hardsect_size[SD_MAJOR(i)] = NULL; + read_ahead[SD_MAJOR(i)] = 0; + } sd_template.dev_max = 0; + if (sd_gendisks != &sd_gendisk) kfree(sd_gendisks); } #endif /* MODULE */ diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/sd.h linux/drivers/scsi/sd.h --- v2.1.125/linux/drivers/scsi/sd.h Fri Jul 31 17:07:58 1998 +++ linux/drivers/scsi/sd.h Fri Oct 16 15:43:09 1998 @@ -42,6 +42,11 @@ extern int revalidate_scsidisk(kdev_t dev, int maxusage); +#define N_SD_MAJORS 8 + +#define SD_MAJOR_MASK (N_SD_MAJORS - 1) +#define SD_PARTITION(i) (((MAJOR(i) & SD_MAJOR_MASK) << 8) | (MINOR(i) & 255)) + #endif /* diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c --- v2.1.125/linux/drivers/scsi/sd_ioctl.c Thu May 7 22:51:51 1998 +++ linux/drivers/scsi/sd_ioctl.c Wed Oct 14 11:43:14 1998 @@ -13,6 +13,7 @@ #include +#define MAJOR_NR SCSI_DISK0_MAJOR #include #include "scsi.h" #include @@ -29,7 +30,7 @@ int diskinfo[4]; struct hd_geometry *loc = (struct hd_geometry *) arg; - SDev = rscsi_disks[MINOR(dev) >> 4].device; + SDev = rscsi_disks[DEVICE_NR(dev)].device; /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it @@ -47,34 +48,34 @@ error = verify_area(VERIFY_WRITE, loc, sizeof(*loc)); if (error) return error; - host = rscsi_disks[MINOR(dev) >> 4].device->host; + host = rscsi_disks[DEVICE_NR(dev)].device->host; /* default to most commonly used values */ diskinfo[0] = 0x40; diskinfo[1] = 0x20; - diskinfo[2] = rscsi_disks[MINOR(dev) >> 4].capacity >> 11; + diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11; /* override with calculated, extended default, or driver values */ if(host->hostt->bios_param != NULL) - host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4], + host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)], dev, &diskinfo[0]); - else scsicam_bios_param(&rscsi_disks[MINOR(dev) >> 4], + else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)], dev, &diskinfo[0]); put_user(diskinfo[0], &loc->heads); put_user(diskinfo[1], &loc->sectors); put_user(diskinfo[2], &loc->cylinders); - put_user(sd[MINOR(inode->i_rdev)].start_sect, &loc->start); + put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start); return 0; case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); if (error) return error; - put_user(sd[MINOR(inode->i_rdev)].nr_sects, + put_user(sd[SD_PARTITION(inode->i_rdev)].nr_sects, (long *) arg); return 0; @@ -110,7 +111,7 @@ RO_IOCTLS(dev, arg); default: - return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg); + return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg); } } diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c --- v2.1.125/linux/drivers/scsi/u14-34f.c Tue Jul 28 14:21:08 1998 +++ linux/drivers/scsi/u14-34f.c Fri Oct 9 11:56:59 1998 @@ -844,12 +844,17 @@ bus_type = "VESA"; } else { + unsigned long flags; sh[j]->wish_block = TRUE; sh[j]->unchecked_isa_dma = TRUE; + + flags=claim_dma_lock(); disable_dma(dma_channel); clear_dma_ff(dma_channel); set_dma_mode(dma_channel, DMA_MODE_CASCADE); enable_dma(dma_channel); + release_dma_lock(flags); + sh[j]->dma_channel = dma_channel; sprintf(BN(j), "U14F%d", j); bus_type = "ISA"; diff -u --recursive --new-file v2.1.125/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.1.125/linux/drivers/scsi/wd7000.c Wed Sep 9 14:51:09 1998 +++ linux/drivers/scsi/wd7000.c Fri Oct 9 11:56:59 1998 @@ -772,10 +772,15 @@ static inline void wd7000_enable_dma (Adapter *host) { + unsigned long flags; host->control |= DMA_EN; outb (host->control, host->iobase + ASC_CONTROL); + + flags = claim_dma_lock(); set_dma_mode (host->dma, DMA_MODE_CASCADE); enable_dma (host->dma); + release_dma_lock(flags); + } diff -u --recursive --new-file v2.1.125/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.125/linux/drivers/sound/Config.in Thu Sep 17 17:53:37 1998 +++ linux/drivers/sound/Config.in Fri Oct 9 11:56:59 1998 @@ -20,11 +20,11 @@ if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then comment 'Compiled-in MSND Classic support requires firmware during compilation.' define_bool CONFIG_MSNDCLAS_HAVE_BOOT y - string ' Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin" - string ' Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin" else define_bool CONFIG_MSNDCLAS_HAVE_BOOT n fi + string ' Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin" + string ' Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin" fi if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then int 'MSND Classic IRQ 5,7,9,10,11,12' CONFIG_MSNDCLAS_IRQ 5 @@ -36,29 +36,29 @@ if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDPIN" = "m" ]; then if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then comment 'Compiled-in MSND Pinnacle support requires firmware during compilation.' - string ' Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin" - string ' Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin" define_bool CONFIG_MSNDPIN_HAVE_BOOT y else define_bool CONFIG_MSNDPIN_HAVE_BOOT n fi + string ' Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin" + string ' Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin" fi if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then int 'MSND Pinnacle IRQ 5,7,9,10,11,12' CONFIG_MSNDPIN_IRQ 5 hex 'MSND Pinnacle memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000 hex 'MSND Pinnacle I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDPIN_IO 290 bool 'MSND Pinnacle has S/PDIF I/O' CONFIG_MSNDPIN_DIGITAL - bool 'MSND Pinnacle Non-PnP Mode' CONFIG_MSNDPIN_NONPNP + bool 'MSND Pinnacle non-PnP Mode' CONFIG_MSNDPIN_NONPNP if [ "$CONFIG_MSNDPIN_NONPNP" = "y" ]; then comment 'MSND Pinnacle DSP section will be configured to above parameters.' - hex 'MSDN Pinnacle config port 250,260,270' CONFIG_MSNDPIN_CFG 250 + hex 'MSND Pinnacle config port 250,260,270' CONFIG_MSNDPIN_CFG 250 comment 'Pinnacle-specific Device Configuration (0 disables)' hex 'MSND Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0 int 'MSND Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0 hex 'MSND Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0 hex 'MSND Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0 int 'MSND Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0 - hex 'MSDN Pinnacle joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0 + hex 'MSND Pinnacle joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0 fi fi if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then @@ -190,6 +190,16 @@ 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 Yamaha OPL3-SA[2,3,x] based (PnP) cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS + if [ "$CONFIG_SOUND_OPL3SA2" = "y" ]; then + hex 'OPL3SA2 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA2_BASE 530 + int 'OPL3SA2 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_IRQ 11 + int 'OPL3SA2 audio DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA 0 + int 'OPL3SA2 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA2 1 + hex 'OPL3SA2 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_OPL3SA2_MPU_BASE 330 + int 'OPL3SA2 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_MPU_IRQ 9 fi dep_tristate 'Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS diff -u --recursive --new-file v2.1.125/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.1.125/linux/drivers/sound/Makefile Thu Sep 17 17:53:37 1998 +++ linux/drivers/sound/Makefile Fri Oct 9 11:56:59 1998 @@ -72,6 +72,7 @@ obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_MSS) += ad1848.o obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o +obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o uart401.o mpu401.o obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o uart401.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_SB) += sb.o uart401.o @@ -219,7 +220,7 @@ ifeq ($(CONFIG_MAUI_HAVE_BOOT),y) maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) bin2hex - bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@ + ./bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@ else maui_boot.h: ( \ diff -u --recursive --new-file v2.1.125/linux/drivers/sound/Readme linux/drivers/sound/Readme --- v2.1.125/linux/drivers/sound/Readme Thu Jul 16 18:09:26 1998 +++ linux/drivers/sound/Readme Fri Oct 9 11:56:59 1998 @@ -168,7 +168,7 @@ with impossible parameters. Check that the application is for sound driver version 2.X or later. -In general the printout of of /dev/sndstat should tell what is the problem. +In general the printout of /dev/sndstat should tell what is the problem. It's possible that there are bugs in the sound driver but 99% of the problems reported to me are caused by somehow incorrect setup during "make config". diff -u --recursive --new-file v2.1.125/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.1.125/linux/drivers/sound/ad1848.c Thu Sep 17 17:53:37 1998 +++ linux/drivers/sound/ad1848.c Fri Oct 9 11:56:59 1998 @@ -206,7 +206,7 @@ return; timeout = 80000; - while (timeout > 0 && ad_read(devc, 11) & 0x20) + while (timeout > 0 && (ad_read(devc, 11) & 0x20)) timeout--; if (ad_read(devc, 11) & 0x20) if (devc->model != MD_1845) @@ -916,7 +916,7 @@ cnt >>= 1; cnt--; - if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + if ((devc->audio_mode & PCM_ENABLE_OUTPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) && intrflag && cnt == devc->xfer_count) { @@ -958,7 +958,7 @@ cnt >>= 1; cnt--; - if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + if ((devc->audio_mode & PCM_ENABLE_INPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) && intrflag && cnt == devc->xfer_count) { @@ -1182,10 +1182,10 @@ unsigned char bits = ad_read(devc, 9); - if (bits & 0x01 && portc->open_mode & OPEN_WRITE) + if (bits & 0x01 && (portc->open_mode & OPEN_WRITE)) ad1848_halt_output(dev); - if (bits & 0x02 && portc->open_mode & OPEN_READ) + if (bits & 0x02 && (portc->open_mode & OPEN_READ)) ad1848_halt_input(dev); devc->audio_mode = 0; } @@ -1308,7 +1308,7 @@ 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, /* Positions 16 to 31 just for CS4231/2 and ad1845 */ - 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -1997,16 +1997,16 @@ ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */ } - if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) + if ((devc->open_mode & OPEN_READ) && (devc->audio_mode & PCM_ENABLE_INPUT) && (alt_stat & 0x20)) { DMAbuf_inputintr(devc->record_dev); } - if (devc->open_mode & OPEN_WRITE && devc->audio_mode & PCM_ENABLE_OUTPUT && - alt_stat & 0x10) + if ((devc->open_mode & OPEN_WRITE) && (devc->audio_mode & PCM_ENABLE_OUTPUT) && + (alt_stat & 0x10)) { DMAbuf_outputintr(devc->playback_dev, 1); } - if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ + if (devc->model != MD_1848 && (alt_stat & 0x40)) /* Timer interrupt */ { devc->timer_ticks++; #if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) diff -u --recursive --new-file v2.1.125/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h --- v2.1.125/linux/drivers/sound/ad1848_mixer.h Thu Jul 16 18:09:26 1998 +++ linux/drivers/sound/ad1848_mixer.h Fri Oct 9 11:56:59 1998 @@ -17,7 +17,7 @@ * The AD1848 codec has generic input lines called Line, Aux1 and Aux2. * Sound card manufacturers have connected actual inputs (CD, synth, line, * etc) to these inputs in different order. Therefore it's difficult - * to assign mixer channels to to these inputs correctly. The following + * to assign mixer channels to these inputs correctly. The following * contains two alternative mappings. The first one is for GUS MAX and * the second is just a generic one (line1, line2 and line3). * (Actually this is not a mapping but rather some kind of interleaving diff -u --recursive --new-file v2.1.125/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.1.125/linux/drivers/sound/audio.c Sat Sep 5 16:46:41 1998 +++ linux/drivers/sound/audio.c Fri Oct 9 11:56:59 1998 @@ -279,7 +279,7 @@ * Nonblocking mode handling. Return current # of bytes */ - if (file->f_flags & O_NONBLOCK && buf_no == -EAGAIN) + if ((file->f_flags & O_NONBLOCK) && buf_no == -EAGAIN) return p; if (p > 0) /* Avoid throwing away data */ diff -u --recursive --new-file v2.1.125/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.1.125/linux/drivers/sound/dev_table.h Sat Sep 5 16:46:41 1998 +++ linux/drivers/sound/dev_table.h Fri Oct 9 11:56:59 1998 @@ -31,6 +31,8 @@ #define SNDCARD_SOFTOSS 36 #define SNDCARD_VMIDI 37 #define SNDCARD_WAVEFRONT 41 +#define SNDCARD_OPL3SA2 42 +#define SNDCARD_OPL3SA2_MPU 43 void attach_opl3sa_wss (struct address_info *hw_config); int probe_opl3sa_wss (struct address_info *hw_config); @@ -412,6 +414,11 @@ {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu}, #endif +#ifdef CONFIG_SOUND_OPL3SA2 + {"OPL3SA2", 0, SNDCARD_OPL3SA2, "OPL3SA2", attach_opl3sa2, probe_opl3sa2, unload_opl3sa2}, + {"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU, "OPL3SA2 MIDI", attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu}, +#endif + #ifdef CONFIG_SGALAXY {"SGALAXY", 0, SNDCARD_SGALAXY, "Sound Galaxy WSS", attach_sgalaxy, probe_sgalaxy, unload_sgalaxy}, #endif @@ -558,6 +565,16 @@ {SNDCARD_CS4232_MPU, {CONFIG_CS4232_MPU_BASE, CONFIG_CS4232_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif {SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE}, +#endif + +#ifdef CONFIG_SOUND_OPL3SA2 +#ifndef CONFIG_OPL3SA2_DMA2 +#define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA +#endif +#ifdef CONFIG_OPL3SA2_MPU_BASE + {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, +#endif + {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_SGALAXY diff -u --recursive --new-file v2.1.125/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.1.125/linux/drivers/sound/dmabuf.c Sat Sep 5 16:46:41 1998 +++ linux/drivers/sound/dmabuf.c Fri Oct 9 11:56:59 1998 @@ -138,15 +138,15 @@ int chan = dmap->dma; /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ - save_flags(flags); - cli(); + + flags = claim_dma_lock(); 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); + release_dma_lock(flags); return 0; } @@ -201,11 +201,17 @@ static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap) { + unsigned long flags; + sound_close_dma(dmap->dma); if (dmap->flags & DMA_BUSY) dmap->dma_mode = DMODE_NONE; dmap->flags &= ~DMA_BUSY; + + flags=claim_dma_lock(); disable_dma(dmap->dma); + release_dma_lock(flags); + sound_free_dmap(dmap); } @@ -279,7 +285,7 @@ } adev->enable_bits = mode; - if (mode == OPEN_READ || (mode != OPEN_WRITE && adev->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) @@ -311,7 +317,7 @@ static void dma_reset_output(int dev) { struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; + unsigned long flags,f ; struct dma_buffparms *dmap = adev->dmap_out; if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ @@ -341,8 +347,12 @@ else adev->d->halt_output(dev); adev->dmap_out->flags &= ~DMA_STARTED; + + f=claim_dma_lock(); clear_dma_ff(dmap->dma); disable_dma(dmap->dma); + release_dma_lock(f); + restore_flags(flags); dmap->byte_counter = 0; reorganize_buffers(dev, adev->dmap_out, 0); @@ -377,7 +387,7 @@ return; /* Don't start DMA yet */ dmap->dma_mode = DMODE_OUTPUT; - if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { + 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)) @@ -404,7 +414,7 @@ int n = 0; struct dma_buffparms *dmap; - if (!adev->go && (!adev->enable_bits & PCM_ENABLE_OUTPUT)) + if (!adev->go && !(adev->enable_bits & PCM_ENABLE_OUTPUT)) return 0; if (adev->dmap_out->dma_mode == DMODE_OUTPUT) { @@ -476,7 +486,7 @@ if (adev->open_mode == OPEN_READ || (adev->open_mode != OPEN_WRITE && - adev->flags & DMA_DUPLEX)) + (adev->flags & DMA_DUPLEX))) close_dmap(adev, adev->dmap_in); adev->open_mode = 0; restore_flags(flags); @@ -606,6 +616,7 @@ int pos; unsigned long flags; + unsigned long f; save_flags(flags); cli(); @@ -613,9 +624,12 @@ pos = 0; else { int chan = dmap->dma; + + f=claim_dma_lock(); 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)) { @@ -634,6 +648,7 @@ if (pos >= dmap->bytes_in_use) pos = 0; enable_dma(dmap->dma); + release_dma_lock(f); } restore_flags(flags); /* printk( "%04x ", pos); */ @@ -961,10 +976,16 @@ } if (!(adev->flags & DMA_AUTOMODE)) dmap->flags &= ~DMA_ACTIVE; - while (dmap->qlen <= 0) { + + /* + * This is dmap->qlen <= 0 except when closing when + * dmap->qlen < 0 + */ + + while (dmap->qlen <= -dmap->closing) { dmap->underrun_count++; dmap->qlen++; - if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) { + 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); @@ -988,10 +1009,15 @@ cli(); if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; + unsigned long f; + + f=claim_dma_lock(); clear_dma_ff(chan); disable_dma(dmap->dma); pos = dmap->bytes_in_use - get_dma_residue(chan); enable_dma(dmap->dma); + release_dma_lock(f); + pos = pos / dmap->fragment_size; /* Actual qhead */ if (pos < 0 || pos >= dmap->nbufs) pos = 0; @@ -1056,7 +1082,7 @@ } } } - if (!(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { + 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) @@ -1078,10 +1104,14 @@ if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; + unsigned long f; + + f=claim_dma_lock(); clear_dma_ff(chan); disable_dma(dmap->dma); pos = dmap->bytes_in_use - get_dma_residue(chan); enable_dma(dmap->dma); + release_dma_lock(f); pos = pos / dmap->fragment_size; /* Actual qhead */ if (pos < 0 || pos >= dmap->nbufs) @@ -1112,11 +1142,10 @@ if (adev->dmap_out->dma >= 0) { unsigned long flags; - save_flags(flags); - cli(); + flags=claim_dma_lock(); clear_dma_ff(adev->dmap_out->dma); disable_dma(adev->dmap_out->dma); - restore_flags(flags); + release_dma_lock(flags); } return 0; } diff -u --recursive --new-file v2.1.125/linux/drivers/sound/legacy.h linux/drivers/sound/legacy.h --- v2.1.125/linux/drivers/sound/legacy.h Thu May 14 19:47:42 1998 +++ linux/drivers/sound/legacy.h Fri Oct 9 11:56:59 1998 @@ -27,6 +27,7 @@ #define CONFIG_MPU401 #define CONFIG_MSS #define CONFIG_OPL3SA1 +#define CONFIG_OPL3SA2 #define CONFIG_PAS #define CONFIG_PSS #define CONFIG_SB diff -u --recursive --new-file v2.1.125/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.1.125/linux/drivers/sound/msnd_pinnacle.c Thu Sep 17 17:53:37 1998 +++ linux/drivers/sound/msnd_pinnacle.c Fri Oct 9 11:56:59 1998 @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_pinnacle.c,v 1.63 1998/09/10 18:37:19 andrewtv Exp $ + * $Id: msnd_pinnacle.c,v 1.65 1998/09/18 19:13:03 andrewtv Exp $ * ********************************************************************/ @@ -1099,7 +1099,9 @@ dev_ioctl, /* ioctl */ NULL, /* mmap */ dev_open, /* open */ +#ifndef LINUX20 NULL, /* flush */ +#endif dev_release, /* release */ NULL, /* fsync */ NULL, /* fasync */ diff -u --recursive --new-file v2.1.125/linux/drivers/sound/opl3sa2.c linux/drivers/sound/opl3sa2.c --- v2.1.125/linux/drivers/sound/opl3sa2.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/opl3sa2.c Fri Oct 9 11:56:59 1998 @@ -0,0 +1,241 @@ +/* + * sound/opl3sa2.c + * + * A low level driver for Yamaha OPL3-SA[2,3,x] based cards. + * + * Scott Murray, Jun 14, 1998 + * + */ + +/* Based on the CS4232 driver: + * + * 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 +#include + +#include "sound_config.h" +#include "soundmodule.h" + +#ifdef CONFIG_OPL3SA2 + +int probe_opl3sa2_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + return probe_mpu401(hw_config); +#else + return 0; +#endif +} + + +void attach_opl3sa2_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + attach_mpu401(hw_config); +#endif +} + + +void unload_opl3sa2_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + unload_mpu401(hw_config); +#endif +} + + +int probe_opl3sa2_mss(struct address_info *hw_config) +{ + return probe_ms_sound(hw_config); +} + + +void attach_opl3sa2_mss(struct address_info *hw_config) +{ + printk(KERN_INFO "opl3sa2.c: trying to init WSS\n"); + + attach_ms_sound(hw_config); + + /* request_region(hw_config->io_base, 4, "Yamaha 7xx WSS Config"); */ + + if (hw_config->slots[0] != -1 && + audio_devs[hw_config->slots[0]]->mixer_dev != -1) + { + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); + /* GSM! test the following: */ + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); + } +} + + +void unload_opl3sa2_mss(struct address_info *hw_config) +{ + int mixer; + + /* Find mixer */ + mixer = audio_devs[hw_config->slots[0]]->mixer_dev; + + /* Unload MSS audio codec */ + unload_ms_sound(hw_config); + + sound_unload_audiodev(hw_config->slots[0]); + + /* Unload mixer if there */ + if(mixer >= 0) + { + sound_unload_mixerdev(mixer); + } + + /* Release MSS config ports */ + release_region(hw_config->io_base, 4); +} + + +int probe_opl3sa2(struct address_info *hw_config) +{ + /* + * Verify that the I/O port range is free. + */ + + printk(KERN_INFO "opl3sa2.c: Control using I/O port 0x%03x\n", hw_config->io_base); + + if (check_region(hw_config->io_base, 2)) + { + printk(KERN_ERR "opl3sa2.c: Control I/O port 0x%03x not free\n", hw_config->io_base); + return 0; + } + + /* GSM!: Add some kind of other test here... */ + + return 1; +} + + +void attach_opl3sa2(struct address_info *hw_config) +{ + printk(KERN_INFO "opl3sa2.c: trying to init!\n"); + + request_region(hw_config->io_base, 2, "Yamaha 7xx Control"); + + /* GSM! Mixer stuff should go here... */ +} + + +void unload_opl3sa2(struct address_info *hw_config) +{ + /* Release control ports */ + release_region(hw_config->io_base, 2); + + /* GSM! Mixer stuff should go here... */ +} + + +#ifdef MODULE + +int io = -1; +int mss_io = -1; +int mpu_io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; + +MODULE_PARM(io,"i"); +MODULE_PARM(mss_io,"i"); +MODULE_PARM(mpu_io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(dma2,"i"); + +EXPORT_NO_SYMBOLS; + +struct address_info cfg; +struct address_info mss_cfg; +struct address_info mpu_cfg; + +/* + * Install a OPL3SA2 based card. Need to have ad1848 and mpu401 + * loaded ready. + */ +int init_module(void) +{ + int i; + + if (io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1) + { + printk(KERN_ERR "opl3sa2: io, mss_io, irq, dma, and dma2 must be set.\n"); + return -EINVAL; + } + + /* Our own config: */ + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; + + /* The MSS config: */ + mss_cfg.io_base = mss_io; + mss_cfg.irq = irq; + mss_cfg.dma = dma; + mss_cfg.dma2 = dma2; + mss_cfg.card_subtype = 1; /* No IRQ or DMA setup */ + + /* Call me paranoid: */ + for(i = 0; i < 6; i++) + { + cfg.slots[i] = mss_cfg.slots[i] = mpu_cfg.slots[i] = -1; + } + + if (probe_opl3sa2(&cfg) == 0) + { + return -ENODEV; + } + attach_opl3sa2(&cfg); + + if (probe_opl3sa2_mss(&mss_cfg) == 0) + { + return -ENODEV; + } + attach_opl3sa2_mss(&mss_cfg); + +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + if(mpu_io != -1) + { + /* MPU config: */ + mpu_cfg.io_base = mpu_io; + mpu_cfg.irq = irq; + mpu_cfg.dma = dma; + mpu_cfg.always_detect = 1; /* It's there, so use shared IRQs */ + + if (probe_opl3sa2_mpu(&mpu_cfg)) + { + attach_opl3sa2_mpu(&mpu_cfg); + } + } +#endif + SOUND_LOCK; + return 0; +} + + +void cleanup_module(void) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + if(mpu_cfg.slots[1] != -1) + { + unload_opl3sa2_mpu(&mpu_cfg); + } +#endif + unload_opl3sa2_mss(&mss_cfg); + unload_opl3sa2(&cfg); + SOUND_LOCK_END; +} + +#endif +#endif diff -u --recursive --new-file v2.1.125/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.1.125/linux/drivers/sound/sb_common.c Thu Sep 17 17:53:37 1998 +++ linux/drivers/sound/sb_common.c Fri Oct 9 11:56:59 1998 @@ -954,8 +954,7 @@ if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && devc->irq > 0) { free_irq(devc->irq, devc); - if (devc->my_mixerdev) - sound_unload_mixerdev(devc->my_mixerdev); + sound_unload_mixerdev(devc->my_mixerdev); /* We don't have to do this bit any more the UART401 is its own master -- Krzysztof Halasa */ /* But we have to do it, if UART401 is not detected */ diff -u --recursive --new-file v2.1.125/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v2.1.125/linux/drivers/sound/sound_calls.h Tue Jul 21 00:15:31 1998 +++ linux/drivers/sound/sound_calls.h Fri Oct 9 11:56:59 1998 @@ -251,6 +251,8 @@ void unload_trix_mpu(struct address_info *hw_info); void unload_cs4232(struct address_info *hw_info); void unload_cs4232_mpu(struct address_info *hw_info); +void unload_opl3sa2(struct address_info *hw_info); +void unload_opl3sa2_mpu(struct address_info *hw_info); /* From cs4232.c */ @@ -258,6 +260,12 @@ void attach_cs4232 (struct address_info *hw_config); int probe_cs4232_mpu (struct address_info *hw_config); void attach_cs4232_mpu (struct address_info *hw_config); + +/* From opl3sa2.c */ +int probe_opl3sa2 (struct address_info *hw_config); +void attach_opl3sa2 (struct address_info *hw_config); +int probe_opl3sa2_mpu (struct address_info *hw_config); +void attach_opl3sa2_mpu (struct address_info *hw_config); /* From maui.c */ void attach_maui(struct address_info * hw_config); diff -u --recursive --new-file v2.1.125/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.1.125/linux/drivers/video/Config.in Mon Oct 5 13:13:40 1998 +++ linux/drivers/video/Config.in Thu Oct 15 15:24:18 1998 @@ -71,6 +71,14 @@ bool ' Leo (ZX) support' CONFIG_FB_LEO fi fi + if [ "$ARCH" = "sparc" ]; then + if [ "$CONFIG_PCI" != "n" ]; then + bool 'PCI framebuffers' CONFIG_FB_PCI + if [ "$CONFIG_FB_PCI" != "n" ]; then + bool ' IGA 168x display support' CONFIG_FB_IGA + fi + fi + fi if [ "$ARCH" = "sparc64" ]; then if [ "$CONFIG_PCI" != "n" ]; then bool 'PCI framebuffers' CONFIG_FB_PCI @@ -133,7 +141,8 @@ "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_G364" = "y" -o \ - "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" ]; then + "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \ + "$CONFIG_FB_IGA" = "y" ]; then define_bool CONFIG_FBCON_CFB8 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ @@ -143,7 +152,8 @@ "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_G364" = "m" -o \ - "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" ]; then + "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \ + "$CONFIG_FB_IGA" = "y" ]; then define_bool CONFIG_FBCON_CFB8 m fi fi diff -u --recursive --new-file v2.1.125/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.1.125/linux/drivers/video/Makefile Mon Oct 5 13:13:40 1998 +++ linux/drivers/video/Makefile Thu Oct 15 15:24:18 1998 @@ -95,6 +95,10 @@ L_OBJS += atyfb.o endif +ifeq ($(CONFIG_FB_IGA),y) +L_OBJS += igafb.o +endif + ifeq ($(CONFIG_FB_CONTROL),y) L_OBJS += controlfb.o endif @@ -447,7 +451,7 @@ include $(TOPDIR)/Rules.make -promcon_tbl.c: prom.uni +promcon_tbl.c: prom.uni ../char/conmakehash ../char/conmakehash prom.uni | \ sed -e '/#include <[^>]*>/p' -e 's/types/init/' \ -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c diff -u --recursive --new-file v2.1.125/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.1.125/linux/drivers/video/atyfb.c Mon Oct 5 13:13:41 1998 +++ linux/drivers/video/atyfb.c Thu Oct 15 15:24:18 1998 @@ -1,4 +1,4 @@ -/* $Id: atyfb.c,v 1.77 1998/09/14 08:01:46 jj Exp $ +/* $Id: atyfb.c,v 1.81 1998/10/14 16:45:38 ecd Exp $ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64 * * Copyright (C) 1997-1998 Geert Uytterhoeven @@ -28,6 +28,8 @@ - cursor support on all cards and all ramdacs. - cursor parameters controlable via ioctl()s. + - guess PLL and MCLK based on the original PLL register values initialized + by the BIOS or Open Firmware (if they are initialized). (Anyone to help with this?) @@ -60,7 +62,7 @@ #include -#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP) +#if defined(CONFIG_PPC) #include #include #include